Պագինացիա և կուրսորներ
1) Ինչո՞ ւ է անհրաժեշտ պագինացիա
Պագինացիան սահմանափակում է և փոխանցվող հաճախորդների տվյալների ծավալը, նվազեցնում է վճարումների/ցանցի բեռը և տալիս է հավաքածուի «քայլելու» դետերմինացված մեթոդ։ Իրական համակարգերում պագինացիան ոչ միայն «page = 1 & limit = 50» է, այլ պրոտոկոլային շարժիչների և ինվարանտների հավաքածու։
Տիպիկ նպատակներ
Լատենտության վերահսկումը և հիշողությունը հարցման համար։
Կայուն ռոտացիան տվյալների հավաքածուի փոփոխման ժամանակ (108/108)։
Հնարավորություն տեղից (resumption)։
Քեշինգը և նախածանցը (www.fetch)։
Պաշտպանություն չարաշահումներից (rate limiting, backpressure)։
2) Սագինացիայի մոդելները
2. 1 MSSET/LIMIT (էջ)
Գաղափարը '«թողեք N տողերը, հավատացեք M»։
Պլյուսներ ՝ պարզություն, համակցված գրեթե ցանկացած SQL/Windows SQL-ի հետ։
Մինուսներ
Գծային քայքայումը 'մեծ SNSET հանգեցնում է ամբողջական սկանավորման/skip-cost։
Անկայունությունը պահանջների միջև տեղադրման/հեռացման ժամանակ («լողում»)։
Դժվար է ապահովել ճշգրիտ «վերականգնումը»։
SQL օրինակ
sql
SELECT
FROM orders
ORDER BY created_at DESC, id DESC
OFFSET 1000 LIMIT 50;
2. 2 Cursor/Keyset/Seek-pagination
Գաղափար. <<շարունակեք K ստեղից>>։ Մոսկվան հեռացված հավաքածուի դիրք է։
Պլյուսներ
O (1) շարունակության հասանելիությունը, երբ կա ինդեքսը։
Տեղադրված է հավաքածուի փոփոխության ժամանակ։
Լավագույն լատենտ խորը «էջերի» վրա։
Մինուսներ
Անհրաժեշտ են խիստ որոշակի, յուրահատուկ և մոնոտոնային տեսակավորման բանալիներ։
Ավելի բարդ է իրականացումը և կարգաբերումը։
SQL օրինակ (seek)
sql
-- Resumption after steam (created_at, id) = (:last_ts,:last_id)
SELECT
FROM orders
WHERE (created_at, id) < (:last_ts,:last_id)
ORDER BY created_at DESC, id DESC
LIMIT 50;
2. 3 Intinuation tokens (անթափանց հոսանքներ)
Գաղափարը 'սերվերը վերադարձնում է opaque-toxen-ը, որտեղ նշվում է «դիրքը» (և հավանաբար շարդի/ֆիլտրերի վիճակը)։ Հաճախորդը չի հասկանում ներսը և պարզապես վերադարձնում է հոսանքը հաջորդ էջի համար։
Պլյուսներ 'ճկունություն, սխեման փոխելու հնարավորություն առանց API-ի։
Մինուսները 'հոսանքների կյանքի տևողության կառավարումը, դոպլոների համատեղելիությունը։
2. 4 Ժամանակավոր և տրամաբանական կուրսորներ
Time-based: «Բոլոր գրառումները մինչև T», կոմպոզիցիան ժամանակի մետր է (հարմար է append-only հոսքերում)։
Log-sequence/wwww.set-based: 108-ը լոգարանում (Kafka set, journal seq)։
Global monotonic IDS: Winowflake/UUIDv7 որպես կայուն sek։
3) Դասընթացների և հոսանքների նախագծումը
3. 1 Լավ կուրսորի հատկությունները
Անթափանցելիությունը (opaque). հաճախորդը կախված չէ ձևաչափից։
Հեղինակություն/ամբողջականություն 'HMAC ստորագրություն, որպեսզի կանխի փոխարինումը/մանիպուլյացիան։
Համատեքստը ներառում է տեսակավորում, ֆիլտրեր, սխեմայի տարբերակը, tenault/shard։
Կյանքի ժամանակահատվածը 'TTL և «աննկատ» (non-replay), երբ փոխում են ինդեքսները/հասանելիության իրավունքները։
Չափը 'կոմպակտ (<= 1-2 KB), որը հարմար է URL-ի համար։
3. 2 Տոկենի ձևաչափը
Առաջարկվող աթոռը 'JSON-ը նկարագրում է սեղմումը (zstd/www.late) www.Base.RUR.RU HMAC-ը։
Բեռի կառուցվածքը (օրինակ)
json
{
"v": 3 ,//token version
"sort": ["created_at:desc","id:desc"],
"pos": {"created_at":"2025-10-30T12:34:56. 789Z","id":"987654321"},
"filters": {"user_id":"42","status":["paid","shipped"]},
"tenant": "eu-west-1",
"shards": [{"s ": "a, "" hi":"..."}] ,//optional: cross-shard context
"issued_at": "2025-10-31T14:00:00Z",
"ttl_sec": 3600
}
Վերևում ավելացվում է «mac = HMAC (secret, payload)» և ամեն ինչ կոդավորվում է մեկ կառուցվածքային հոսանքի մեջ։
3. 3 Անվտանգություն
Ստորագրել (HMAC/SHA-256)։
Օբյեկտիվ կոդավորում (AES-GCM) զգայուն արժեքների առկայության դեպքում (PII)։
Սերվերի վրա վալիդացիան 'տարբերակը, TTL, օգտագործողի (RBAC/ABAC)։
4) Ներդաշնակությունը և ինվարանտները
4. 1 Կայուն տեսակավորում
Օգտագործեք ամբողջական դետերմինիզմ '«ORDER BY ts DESC, id DESC»։
Տեսակավորման բանալին պետք է յուրահատուկ լինի (ավելացրեք 'id' որպես tiebreaker)։
Ինդեքսը պետք է համապատասխանի տեսակավորմանը (covering index)։
4. 2 Նկար (www.apshot) և մեկուսացում
«Անպաշտպան» էջերի համար օգտագործեք read-consistent diapshot (MVCC/txid)։
Եթե կեղևը նպատակաուղղված չէ (թանկ/շատ տվյալներ), ձևակերպեք պայմանագիրը. <<Ռուսական վերադարձնում է տարրերը, խստորեն նախկինում դիրքը>>։ Դա բնական է նորությունների համար։
4. 3 Tramp/www.ru էջերի միջև
Seek-մոդելը նվազեցնում է «կրկնօրինակներ/բացթողումներ»։
Փաստարկեք վարքագիծը հեռացնելիս/փոփոխելիս, հազվագյուտ «անցքեր» թույլատրվում են էջերի միջև, բայց ոչ «ժամանակ առաջ»։
5) Ինդեքսավորում և կոդավորող սխեմաներ
Կոմպոզիտային ինդեքսները խստորեն տեսակավորման կարգով '«(created _ at DESC, id DESC)»։
Մոնոտոնային ID ՝ Winowflake/UUIDv7-ը ժամանակ է տալիս արագացնել seek։
Տաք բանալիներ 'բաժանեք shard-key (օրինակ ՝ «tenium _ id», «region») և տեղավորեք շարդի ներսում։
Գեներատորներ ID 'խուսափեք կոնֆլիկտներից և «ապագայի ժամերից» (clock skew) - ժամանակի համաժամեցում, «ռեգրեսիա» NTP ցատկում։
6) Cross-sharda pagination
6. 1 Սխեմաներ
Scatter-Gather: Զուգահեռ հարցումներ բոլոր գնդակների, տեղական seek դասընթացների, ապա k-way merge-ի վրա։
Per-Shard Cursors: Թոկենը յուրաքանչյուր շարքի դիրքեր է պարունակում։
Bounded fan-out: Սահմանափակեք շարքերի քանակը մեկ քայլով (rate limiting/timeout budget)։
6. 2 Toxen i-shard
Պահեք www.'d _ id, lection _ pos _>։ Հաջորդ հանդիպման ժամանակ վերականգնեք յուրաքանչյուր ակտիվ գնդակի համար և կրկին մեռնեք ՝ տալով գլոբալ հեռացված էջ։
7) Պրոտոկոլային պայմանագրերը
7. 1 REST
Հարցումը
GET /v1/orders? limit=50&cursor=eyJ2IjoiMyIsInNvcnQiOiJjcmVh... (opaque)
Պատասխանը
json
{
"items": [ /... / ],
"page": {
"limit": 50,
"next_cursor": "eyJ2IjozLCJwb3MiOiJjcmVh...==",
"has_more": true
}
}
Առաջարկություններ
«limit» -ը վերին սահմանից (օրինակ, max = 200)։
«next _ cursor» բացակայում է, եթե «has _ more = false»։
Idempotention GET, պատասխանների հավասարակշռություն առանց «next _ cursor» (առաջին էջը ֆիքսված ֆիլտրերի և www.apshot)։
7. 2 GraphQL (Relay-մոտեցում)
Բնորոշ պայմանագիրը 'connational'։
graphql type Query {
orders(first: Int, after: String, filter: OrderFilter): OrderConnection!
}
type OrderConnection {
edges: [OrderEdge!]!
pageInfo: PageInfo!
}
type OrderEdge {
node: Order!
cursor: String! // opaque
}
type PageInfo {
hasNextPage: Boolean!
endCursor: String
}
«cursor» -ը պետք է լինի անթափանց և ստորագրված։ մի օգտագործեք «Base64 (id)» առանց HMAC-ի։
7. 3 gRPC
Օգտագործեք «page _ size» և «page _ token»։
proto message ListOrdersRequest {
string filter = 1;
int32 page_size = 2;
string page_token = 3; // opaque
}
message ListOrdersResponse {
repeated Order items = 1;
string next_page_token = 2; // opaque bool has_more = 3;
}
7. 4 Հոսք և WindSockets
Շարունակական ժապավենի համար 'նշվում է որպես «վերջին տեսանելի www.set/ts»։
Աջակցեք «resume _ from» ռեկոնեկտով
json
{ "action":"subscribe", "topic":"orders", "resume_from":"2025-10-31T12:00:00Z#987654321" }
8) Քեշինգը, բեռնումը, CDN-ը
ETag/If-None-Match-ը առաջին էջի համար կայուն ֆիլտրերով։
Cache-Corl-ը կարճ TTL-ով (օրինակ, 5-30 s) հանրային ցուցակների համար։
Difetch: Վերադարձեք "next _ cursor" և ("Link: Rel =" next "), հաճախորդը կարող է կանխել հաջորդ էջը։
Տատանումները 'հաշվի առեք
9) Բեռի կառավարումը և սահմանազատումը
Վերին սահմանը 'limit ", օրինակ 200։
Server-side backpressure: Եթե հարցման ժամանակը> budget, նվազեցրեք «limit» պատասխանը (և ակնհայտորեն տեղեկացրեք հաճախորդին էջի իրական չափը)։
Rate limits-ը օգտագործողի/tocen/tenae-ի վրա։
Timeout/Retry: էքսպոնենցիալ դադար, գաղափարական կրկնվող հարցումներ։
10) UX ասպեկտները
Սկրոլը համարակալման դեմ 'անսահման շրջադարձային դասընթացներ։ էջերը www.set (բայց բացատրեք անճշտությունը տվյալների նորարարման ժամանակ)։
«Վերադառնալ տեղում» կոճակը պահեք հաճախորդի դասընթացների աթոռը։
Դատարկ էջեր ՝ եթե «has _ more = false», մի ցույց տվեք «Դեռ» կոճակը։
Կայուն սահմաններ 'ցույց տվեք ճշգրիտ «total» միայն եթե այն էժան է (հակառակ դեպքում' մոտավոր «approx _ total»)։
11) Փորձարկումներ և edge-cass
Չեք թերթերը
Կայուն տեսակավորում 'նույն «ts» -ի տարրերը չեն «գաղթում»։
Մոսկվան/2019 'էջերի հանգույցի վրա կրկնություններ չեն հայտնվում։
Էջերի միջև ֆիլտրերի փոփոխությունը 'հոսանքը պետք է շեղվի որպես «հնացած/անհամատեղելի»։
TTL թոկենը 'ճիշտ սխալ ժամկետի համար։
Մեծ խորություն 'լատենտությունը գծային չի աճում։
Multishard: ճիշտ merge կարգը, starvation «դանդաղ» շարդի բացակայությունը։
Property-based թեստի (կեղծ) օրինակ
python
Generate N entries with random inserts between calls
Verify that all pages are merged = = whole ordered fetch
12) Դիտարկումը և SLO-ն
Մետրիկները
«list _ request _ latency _ 24» (P50/P95/P99) աղյուսակում։
«seek _ index _ hit _ ratio» (հարցումների մի մասը, որոնք դուրս են եկել ծածկող ինդեքսով)։
«next _ cursor _ entalid _ rate» (վալիդացիայի/TTL/ստորագրության սխալներ)։
«merge _ fanout» (col-ներգրավված գնդակների վրա էջի վրա)։
«duplicates _ on _ boundary» և «gaps _ on _ boundary» (մանկական հաճախորդի հեռուստատեսության վրա)։
Լոգա/թրեյսինգ
Հարաբերեք «cursor _ id» լոգարաններում, դիմեք payload-ին։
Tegirured '«page _ size», «source _ shards», «db _ index _ used»։
SLO օրինակ
Հասանելիություն ՝ 99։ 9 տոկոսը 'List' մեթոդներով։
Լատենտություն: P95 <200 ms «page _ size <= 50» տեղական շարքով։
Թոկենի սխալը '<0։ զանգերի ընդհանուր թվի 1% -ը։
13) Մոսկվան և համատեղելիությունը
Միացրեք «v» -ը և աջակցեք N շաբաթվա հին տարբերակները։
Եթե փոխեք համապատասխան տեսակավորումը, ուղարկեք «փափուկ» սխալը '«409 Sylict», որը հուշում է թարմ տերևներ առանց կուրսորի։
Աղետալի դեպք (բոլոր հոսանքների հեղափոխություն) 'փոխեք «signing _ key _ id» և շեղեք հինը։
14) Իրականության օրինակներ
14. 1 Տոկենի գեներացիան (կեղծ)
python payload = json. dumps({...}). encode()
compressed = zlib. compress(payload)
mac = hmac_sha256(signing_key, compressed)
token = base64url_encode(mac + compressed)
14. 2 Տոկիոյի վալիդացիա
python raw = base64url_decode(token)
mac, compressed = raw[:32], raw[32:]
assert mac == hmac_sha256(signing_key, compressed)
payload = json. loads(zlib. decompress(compressed))
assert now() - payload["issued_at"] < payload["ttl_sec"]
assert payload["filters"] == req. filters
14. 3 Seek-հարցումը կոմպոզիտային բանալին
sql
-- Page # 1
SELECT FROM feed
WHERE tenant_id =:t
ORDER BY ts DESC, id DESC
LIMIT:limit;
-- Next pages, continued after (ts0, id0)
SELECT FROM feed
WHERE tenant_id =:t
AND (ts <:ts0 OR (ts =:ts0 AND id <:id0))
ORDER BY ts DESC, id DESC
LIMIT:limit;
15) Անվտանգություն և համապատասխանություն
Մի՛ միացրեք հում դաշտերը, որոնցից կարելի է դուրս բերել PII-ը։
Ստորագրեք և սահմանափակեք TTL-ը։
Փորձիր հոսել օգտագործողների միջև անհանդուրժող (մակագրեք 'sub/tenae/roles "-ը payload-ում և նվազեցրեք վալիդացիայի ժամանակ)։
Տրամաբանեք միայն հոսանքների հեշը։
16) Հաճախակի սխալներ և հակատիպեր
Base64 (id) որպես ստանդարտ, հեշտ է կեղծել/ընտրել, կոտրել պայմանագիրը տեսակավորման փոփոխության ժամանակ։
Tie-breaker: "ORDER BY ts DESC" առանց "id 'no կրկնօրինակներ/ցատկ։
Ֆիլտրերի փոփոխությունը էջերի միջև առանց հոսանքի։
Խորը SNSET 'դանդաղ և անկանխատեսելի։
Տոկենները առանց տարբերակի և TTL-ի։
17) Ներդրման մինի-չեկլիստ
1. Ռուսական տեսակավորումը և ավելացրեք յուրահատուկ tie-breaker։
2. Տեղադրեք ծածկող ինդեքսը այս կարգի տակ։
3. Ընտրեք մոդել 'seek + անթափանց հոսանք։
4. Իրականացրեք ստորագրությունը (և, անհրաժեշտության դեպքում, կոդավորումը)։
5. Տեղադրեք TTL-ը և տարբերակումը։
6. Կազմեք և հետևեք պայմանագրերին «has _ more», «next _ cursor»։
7. Մտածեք Քրոս Շարդի սխեման (անհրաժեշտության դեպքում) և k-way merge-ը։
8. Ավելացրեք մետրերը, ալերտները և SLO-ը։
9. Վերցրեք property-based-ը էջերի սահմանների փորձարկումներով։
10. Նկարագրեք հոսանքների միգրաֆիկ ռազմավարությունը։
18) Հակիրճ առաջարկություններ ՝ մոտեցում ընտրելու համար
Պիտեր/որոնում, որտեղ կարևոր է «էջի համարը» և մոտավոր total: Ենթադրենք 'SDSET/LIMIT' + kash; տեղեկացրեք, որ total-ը մոտավոր է։
Ժապավենները, վերլուծությունը, խորը ցուցակները, բարձր RPS: միայն cursor/seek։
Շարդեն/բաշխված հավաքածուներ ՝ per-shard cursors + merge tocen։
Հոսքերը/CDC: կուրսորները որպես www.sets/ts վերականգնումով։
19) API պայմանագրի օրինակ (ռեզյումե)
`GET /v1/items? limit=50&cursor=...`
Պատասխանը միշտ ներառում է «page»։ limit`, `page. has _ more ", oporational 'page։ next_cursor`.
Ռուսական անթափանց, ստորագրված, TTL-ից։
Տեսակավորումը դետերմինացված է '«ORDER BY created _ at DESC, id DESC»։
Վարքագիծը, երբ փոփոխվում է, տարրերը չեն «վերադառնում» դասընթացի հետ կապված։
Մետրիկներն ու սխալները ստանդարտացված են ՝ «www.alid _ cursor», «expired _ cursor», «mismatch _ www.ters»։
Այս հոդվածը տալիս է ճարտարապետական սկզբունքներ և պատրաստի փամփուշտներ, որպեսզի նախագծեն պագինացիա, որը մնում է արագ, կանխատեսելի և անվտանգ նույնիսկ մեծ տվյալների, շարդինգի և ակտիվորեն փոփոխվող ձայնագրությունների հավաքածուների պայմաններում։