Paginasiýa we kursorlar
1) Näme üçin paginasiýa gerek?
Paginasiýa müşderi tarapyndan berilýän we görkezilýän maglumatlaryň mukdaryny çäklendirýär, ammarlara/torlara ýüküni azaldýar we kolleksiýa boýunça "ýöremegiň" kesgitlenen usulyny kesgitleýär. Hakyky ulgamlarda paginasiýa diňe 'page = 1 & limit = 50' däl, eýsem teswirnama şertnamalarynyň we ylalaşygyň üýtgemeleriniň toplumydyr.
Adaty maksatlar:- Soraga gizlinligi we ýady barlamak.
- Maglumat toplumy üýtgäninde durnukly nawigasiýa (goýma/aýyrma).
- Ýerinden täzeden başlamak mümkinçiligi (resumption).
- Kesmek we öňünden ýüklemek (prefetch).
- Hyýanatçylykdan goramak (rate limiting, backpressure).
2) Paginasiýa modelleri
2. 1 OFFSET/LIMIT (sahypaly)
Pikir: "N setirleri sypdyryň, M-ni yzyna gaýtaryň".
Artykmaçlyklary: ýönekeýlik, islendik SQL/NoSQL bilen gabat gelýär.
- Çyzykly zaýalanma: uly OFFSET-ler doly skanirlemäge/skip-cost-a sebäp bolýar.
- Soraglaryň arasynda goýlanda/aýyrylanda durnuksyzlyk (süýşmeler "ýüzýär").
- Takyk "täzelenip bilmek" kyn.
sql
SELECT
FROM orders
ORDER BY created_at DESC, id DESC
OFFSET 1000 LIMIT 50;
2. 2 Cursor/Keyset/Seek-paginasiýa
Pikir: "K açaryndan dowam et". Kursor sortlanan toplumdaky ýerdir.
Plýuslar:- O (1) indeksiň barlygynda dowamy üçin elýeterlilik.
- Kolleksiýa üýtgedilende durnuklylyk.
- Çuňňur "sahypalarda" iň gowy gizlinlik.
- Gaty kesgitlenen, özboluşly we monoton sortlamak açarlary gerek.
- Durmuşa geçirmek we düzetmek has kyn.
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 Continuation tokens (aç-açan däl tokenler)
Ideýa: serwer "pozisiýa" kodlanan opaque-tokeni (we belki şard/süzgüçleriň ýagdaýy) yzyna gaýtarýar. Müşderi içeri düşünenok we diňe indiki sahypa üçin belligi yzyna berýär.
Artykmaçlyklary: çeýeligi, API-ni bozmazdan shemany üýtgetmek ukyby.
Minuslar: tokenleriň ömrüni dolandyrmak, deplolarda gabat gelmek.
2. 4 Wagtlaýyn we logiki kursorlar
Time-based: "T çenli ähli ýazgylar", kursor - wagt belligi (append-only akymlarda amatly).
Log-sequence/offset-based: kursor - göçme (Kafka offset, journal seq).
Global monotonic IDs: Snowflake/UUIDv7 seek üçin sortlanan açarlar hökmünde.
3) Kurslaryň we bellikleriň dizaýny
3. 1 Gowy kursoryň aýratynlyklary
Aç-açanlyk (opaque): Müşderi formatyna bagly däl.
Awtorlyk/bitewilik: çalyşmagyň/manipulýasiýanyň öňüni almak üçin HMAC goly.
Kontekst: sortlamany, süzgüçleri, shemanyň wersiýasyny, tenant/shard.
Ömri: TTL we indeks/giriş hukugy üýtgän mahaly "göçürilmezlik".
Ölçegi: ykjam (<= 1-2 KB), URL üçin amatly.
3. 2 Token görnüşi
Maslahat berilýän yığını: JSON → gysyş (zstd/deflate) → Base64URL → HMAC.
Peýdaly ýüküň gurluşy (mysal):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
}
Ýokardan 'mac = HMAC (secret, payload)' goşulýar we hemme zat bir setir belligine kodlanýar.
3. 3 Howpsuzlyk
Gol çekiň (HMAC/SHA-256).
Duýgur gymmatlyklar (PII) bar bolsa, (AES-GCM) goşmaça şifrlemek.
Serwerde tassyklama: wersiýa, TTL, ulanyjynyň ygtyýarlyklary (RBAC/ABAC).
4) Ylalaşyklylyk we üýtgewsizlikler
4. 1 Durnukly sortlamak
Doly determinizmi ulanyň: 'ORDER BY ts DESC, id DESC'.
Sortlamak açary özboluşly bolmaly ('id' -ni tiebreaker hökmünde goşuň).
Indeks sortlanmaga laýyk gelmelidir (covering index).
4. 2 Suratlar (snapshot) we izolýasiýa
"Syzdyrmaýan" sahypalar üçin read-consistent snapshot (MVCC/txid) ulanyň.
Snapshot ýerliksiz bolsa (gymmat/köp maglumat), şertnamany düzüň: "kursor pozisiýadan has öň elementleri yzyna gaýtarýar". Bu habar lentalary üçin tebigy zat.
4. 3 Sahypalaryň arasynda goýmalar/aýyrmalar
Seek-model "dublikatlar/geçişler" iň az.
Aýyrylanda/üýtgedilende özüni alyp barşyny dokumentleşdiriň: sahypalaryň arasynda seýrek "deşiklere" ýol berilýär, ýöne "yza" däl.
5) Indeksirlemek we kesgitleýjileriň shemalary
Kompozisiýa indeksleri gaty tertipli: '(created_at DESC, id DESC)'.
Monoton ID: Snowflake/UUIDv7 wagt tertibini berýär → seek çaltlaşdyrýar.
Gyzgyn açarlar: shard-key ('tenant _ id', 'region') arkaly paýlaň we çarçuwanyň içinde tertipläň.
ID generatorlary: Geljekdäki gapma-garşylyklardan we "sagatlardan" gaça duruň (clock skew) - wagt sinhronizasiýasy, NTP böküşlerinde "regressiýa".
6) Çapraz-çarda paginasiýasy
6. 1 Shemalar
Skatter-Gather: ähli şarlara, ýerli gözleg kurslaryna, soňra agregatorda k-way merge paralel soraglar.
Per-Shard Cursors: Token her şard üçin pozisiýalary öz içine alýar.
Bounded fan-out: bir ädimde şard sanyny çäklendiriň (rate limiting/timeout budget).
6. 2 Multi-shard üçin bellikler
{shard _ id, last_pos}'. Indiki ädimde, her bir işjeň eşik üçin täzeden başlaň we global sortlanan sahypany beriň.
7) Teswirnama şertnamalary
7. 1 REST
Haýyş:
GET /v1/orders? limit=50&cursor=eyJ2IjoiMyIsInNvcnQiOiJjcmVh... (opaque)
Jogap:
json
{
"items": [ /... / ],
"page": {
"limit": 50,
"next_cursor": "eyJ2IjozLCJwb3MiOiJjcmVh...==",
"has_more": true
}
}
Teklipler:
- 'limit' (mysal üçin, max = 200).
- 'next _ cursor', eger 'has _ more = false'.
- GET idempotentligi, 'next _ cursor' -syz jogaplaryň keselmegi (süzgüçlerde we snapshotda birinji sahypa).
7. 2 GraphQL (Relay-çemeleşme)
Adaty 'connection' şertnamasy: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' aç-açan we gol çekmeli; HMAC bolmasa "çig Base64 (id)" ulanmaň.
7. 3 gRPC
'page _ size' we 'page _ token' ulanyň: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 Akymlar we WebSockets
Üznüksiz lentalar üçin: kursor "iň soňky gören offset/ts".
reconnect 'resume _ from' tutuň:json
{ "action":"subscribe", "topic":"orders", "resume_from":"2025-10-31T12:00:00Z#987654321" }
8) Kesmek, öňünden ýüklemek, CDN
Durnukly süzgüçli birinji sahypa üçin ETag/If-None-Match.
Jemgyýetçilik sanawlary üçin gysga TTL (mysal üçin 5-30 s) bilen Cache-Control.
Prefetch: 'next _ cursor' we maslahatlary ('Link: rel =' next '') yzyna gaýtaryň, müşderi indiki sahypany öňünden ýükläp biler.
Üýtgeşmeler: 'filter/sort/locale/tenant' -y keshiň bir bölegi hökmünde göz öňünde tutuň.
9) Ýüküň dolandyrylmagy we çäklendirilmegi
Iň ýokary çägi 'limit', mysal üçin 200.
Server-side backpressure: Eger haýyş wagty> budget bolsa, jogap hökmünde 'limit' -ni azaldyň (we sahypanyň hakyky ululygyny müşderä aýdyň).
Rate limits/token/tenant.
Timeout/Retry: eksponent arakesme, idempotent gaýtalanýan soraglar.
10) UX taraplary
Belgä garşy skroll: tükeniksiz aýlaw → kursorlar; belgili sahypalar → offset (ýöne maglumatlary täzeläniňizde nädogrylygy düşündiriň).
"Ýerine gaýdyp gelmek" düwmesi: Müşderiniň kursorlaryny saklaň.
Boş sahypalar: 'has _ more = false' bolsa, "Has köp" düwmesini görkezmäň.
Durnukly çäkler: Diňe arzan bolsa takyk 'total' görkeziň (ýogsam takmynan 'approx _ total').
11) Synag we edge-wakalar
Çek sahypalary:- Durnukly sortlama: birmeňzeş 'ts' elementleri "ýakylmaýar".
- Goýmalar/Aýyrmalar: sahypalaryň çatrygynda gaýtalanmalar görünmeýär.
- Sahypalaryň arasyndaky süzgüçleriň üýtgemegi: belgi "köne/gabat gelmeýän" hökmünde gyşarmaly.
- TTL belligi: möhleti gutarandan soň dogry ýalňyşlyk.
- Uly çuňluk: gizlinlik çyzykly ösmeýär.
- Multişard: dogry merge-tertip, starvation "haýal" şardlaryň ýoklugy.
python
Generate N entries with random inserts between calls
Verify that all pages are merged = = whole ordered fetch
12) Synlamak we SLO
Metrikler:- Sahypanyň uzynlygy boýunça 'list _ request _ latency _ ms' (P50/P95/P99).
- 'seek _ index _ hit _ ratio' (örtük indeksi boýunça giden haýyşlaryň paýy).
- 'next _ cursor _ invalid _ rate' (tassyklama ýalňyşlyklary/TTL/gollar).
- 'merge _ fanout' (sahypadaky ulanylan şardlaryň sany).
- 'duplicates _ on _ boundary' we 'gaps _ on _ boundary' (müşderi telemetriýasyndaky detekt).
- 'cursor _ id' -ni bloglarda baglanyşdyryň, payload-y maskalaň.
- Spanlary belläň: 'page _ size', 'source _ shards', 'db _ index _ used'.
- Elýeterlilik: 99. 'List' usullarynda 9%.
- Gizlinlik: P95 <200 ms for 'page _ size <= 50' lokal çarda.
- Belgi hatasy: <0. Jaňlaryň umumy sanyndan 1%.
13) Migrasiýa we gabat gelmek
Bellikde 'v' -ni açyň we N hepdäniň köne wersiýalaryny saklaň.
Sortlamak açarlaryňyzy üýtgedeniňizde, '409 Conflict' -iň "ýumşak" hatasyny görkezmesiz täze listinge iberiň.
Betbagtçylykly waka: 'signing _ key _ id' -ni üýtgediň we eskilerini ret ediň.
14) Amala aşyrmagyň mysallary
14. 1 Token öndürmek (psevdokod)
python payload = json. dumps({...}). encode()
compressed = zlib. compress(payload)
mac = hmac_sha256(signing_key, compressed)
token = base64url_encode(mac + compressed)
14. 2 Belligi tassyklamak
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 Kompozit açar bilen gözleg
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) Howpsuzlyk we laýyklyk
PII çykaryp boljak çig meýdanlary belliklere goşmaň.
TTL-e gol çekiň we çäklendiriň.
Ulanyjylaryň arasynda çydamsyz bellikler goýmaga synanyşyň ('sub/tenant/roles' -ni "payload" -a ýazyň we tassyklananda barlaň).
Diňe token heşlerini belläň.
16) Ýygy-ýygydan ýalňyşlyklar we anti-patternler
Base64 (id) kursor hökmünde: ýasamak/almak aňsat, sortlamak çalşylanda şertnamany bozýar.
Tie-breaker ýoklugy: 'ORDER BY ts DESC' -siz 'id' → dublikatlar/böküşler.
Bellik etmezden sahypalaryň arasyndaky süzgüçleri üýtgetmek.
Çuňňur OFFSET: haýal we öňünden aýdyp bolmajak.
TTL wersiýasy bolmadyk bellikler.
17) Ornaşdyrmagyň kiçi barlag sanawy
1. Sortlamany kesgitläň we özboluşly tie-breaker goşuň.
2. Şu tertipde örtük indeksini dörediň.
3. Model saýlaň: seek + aç-açan däl token.
4. Belligiň goluny (we zerur bolsa şifrlemek) ýerine ýetiriň.
5. TTL we wersiýa goýuň.
6. "has _ more", "next _ cursor" şertnamalaryny düzüň we resminamalaşdyryň.
7. Kross-şard shemasy (zerur bolsa) we k-way merge barada pikirleniň.
8. Metrler, aladalar we SLO goşuň.
9. Sahypalaryň çäklerini property-based synaglary bilen örtüň.
10. Bellikleriň migrasiýa strategiýasyny beýan ediň.
18) Çemeleşmäni saýlamak boýunça gysgaça teklipler
"Sahypa belgisi" we takmynan total möhüm bolan kataloglar/gözlegler: mysal üçin 'OFFSET/LIMIT' + keş; Jemi çak edilýändigini habar beriň.
Lentalar, analitika, çuňňur sanawlar, ýokary RPS: diňe cursor/seek.
Şardlanan/paýlanan kolleksiýalar: per-shard cursors + merge token.
Akymlar/CDC: kursorlar täzelenen offsets/ts.
19) API ylalaşygynyň mysaly (rezýume)
`GET /v1/items? limit=50&cursor=...`
Jogap elmydama 'page' -ni öz içine alýar. limit`, `page. has_more', goşmaça 'page. next_cursor`.
Aç-açan däl, gol çekilen kursor, c TTL.
Sortlama kesgitlenildi: 'ORDER BY created_at DESC, id DESC'.
Terbiýe üýtgäninde özüni alyp barşy: elementler kursor bilen deňeşdirilende "yzyna" gaýtarylmaýar.
Metrikler we ýalňyşlyklar standartlaşdyryldy: 'invalid _ cursor', 'expired _ cursor', 'mismatch _ filters'.
Bu makala, hatda uly maglumatlar şertlerinde-de çalt, öňünden aýdyp boljak we howpsuz bolup durýan paginasiýany dizaýn etmek üçin binagärlik ýörelgelerini we taýýar nusgalary berýär.