GH GambleHub

Пагинация жана курсорлор

1) Эмне үчүн пагинация керек

Пагинация кардар тарабынан берилген жана рендерилген маалыматтардын көлөмүн чектейт, сактоочу жайларга/тармактарга жүктү азайтат жана коллекция боюнча детерминацияланган "сейилдөө" ыкмасын белгилейт. Чыныгы системаларда пагинация - бул 'page = 1 & limit = 50' гана эмес, протоколдук контракттардын жана ырааттуулуктун инварианттарынын жыйындысы.

Типтүү максаттары:
  • өтүнүч боюнча жашыруун жана эс контролдоо.
  • маалымат топтому өзгөргөндө туруктуу багыттоо (киргизүү/алып салуу).
  • калыбына келтирүү мүмкүнчүлүгү (resumption).
  • кэш жана алдын ала жүктөө (prefetch).
  • кыянаттык менен коргоо (rate limiting, backpressure).

2) Пагинация моделдери

2. 1 OFFSET/LIMIT (барактык)

Идея: "N саптар сагынам, кайра M".
Артыкчылыктары: жөнөкөйлүк, дээрлик ар кандай SQL/NoSQL менен шайкеш келет.

Кемчиликтери:
  • Сызыктуу деградация: чоң OFFSET толук сканерлөө/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 Continuation tokens (тунук эмес токендер)

Идея: сервер "позиция" коддолгон opaque токенин кайтарып берет (жана балким, шардалардын/фильтрлердин абалы). Кардар ичин түшүнбөйт жана жөн гана кийинки бет үчүн токенди кайтарып берет.
Артыкчылыктары: ийкемдүүлүк, API сындыруусуз схемасын өзгөртүү мүмкүнчүлүгү.
Минустары: Токендердин жашоо мөөнөтүн башкаруу, деплояларда шайкештиги.

2. 4 Убакыт жана логикалык курсорлор

Time-based: "Т чейин бардык жазуулар", курсор - убакыт белгиси (append-only агымдарда ылайыктуу).
Log-sequence/offset-based: курсор - логиндеги жылыш (Kafka offset, journal seq).
Global monotonic ID: Snowflake/UUIDv7 туруктуу seek үчүн сорттолгон ачкычтар катары.

3) Курстарды жана токендерди долбоорлоо

3. 1 жакшы курсор касиеттери

Opacity (opaque): кардар формат көз каранды эмес.
Authority/бүтүндүгү: HMAC кол алмаштыруу/манипуляция алдын алуу.
Контекст: сорттоо кирет, чыпкалар, схема версия, tenant/shard.
Өмүр: TTL жана "кол тийбестик" (non-replay) индекстерин/кирүү укугун өзгөртүү.
Көлөмү: компакт (<= 1-2 KB), URL үчүн жарактуу.

3. 2 Токендин форматы

Сунушталган стек: JSON → кысуу (zstd/deflate) → Base64URL → 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 Сүрөттөр (snapshot) жана изоляция

"Кысылбаган" барактар үчүн read-consistent snapshot (MVCC/txid) колдонуңуз.
Эгерде снапшот максатка ылайыксыз болсо (кымбат/көп маалыматтар), келишимди түзүңүз: "курсор позициядан мурда элементтерди кайтарат". Бул кабар тасмалар үчүн табигый нерсе.

4. 3 Беттердин ортосундагы кошумчалар/өчүрүүлөр

Seek модели минималдаштырат "дубликат/пропуск".
Алып салуу/өзгөртүү учурунда жүрүм-турумун документтештирүү: беттердин ортосунда сейрек кездешүүчү "тешиктерге" жол берилет, бирок "убакыттын өтүшү менен артка" эмес.

5) Индекстөө жана идентификатор схемалары

Композициялык индекстер катуу сорттоо тартибинде: '(created_at DESC, id DESC)'.
Monoton ID: Snowflake/UUIDv7 убакыт тартибин берет → тез издөө.
Hot Keys: shard-key боюнча бөлүштүрүү (мисалы, 'tenant _ id', 'region') жана баш оона ичинде сорттоо.
ID генераторлору: кагылышуулардан жана "келечектеги сааттардан" (clock skew) - убакытты синхрондоштуруу, NTP секирүү учурунда "регрессия".

6) Кросс-шард пагинация

6. 1 Схемалар

Scatter-Gather: бардык шар параллелдүү суроолор, жергиликтүү seek курстар, андан кийин k-way өлчөө агрегатору боюнча.
Per-Shard Cursors: Токен ар бир шард боюнча кызмат орундарын камтыйт.
Bounded fan-out: бир кадам үчүн шардалардын санын чектөө (rate limiting/timeout budget).

6. 2 multi-shard үчүн токендер

'{shard _ id, last_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' болсо жок.
  • GET ыктымалдыгы, жооптордун кэшдүүлүгү 'next _ cursor' (белгиленген чыпкалар жана snapshot менен биринчи бет).

7. 2 GraphQL (Relay-мамиле)

Типтүү келишим 'connection':
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' ачык эмес жана кол коюлушу керек; HMAC жок "чийки Base64 (id)" колдонбогула.

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 агымдары жана WebSockets

үзгүлтүксүз тасмалар үчүн: курсор катары "акыркы көргөн offset/ts".

reconnect 'resume _ from' колдоо:
json
{ "action":"subscribe", "topic":"orders", "resume_from":"2025-10-31T12:00:00Z#987654321" }

8) Кэш, алдын ала жүктөө, CDN

ETag/If-None-Match туруктуу чыпкалар менен биринчи бет үчүн.
кыска TTL менен Cache-Control (мисалы, 5-30 с) коомдук тизмелер үчүн.
Prefetch: кайтаруу 'next _ cursor' жана жардам ('Link: rel = "next"'), кардар кийинки баракты жүктөп алат.
Вариация: эске алуу 'filter/sort/locale/tenant' кэш бөлүгүнүн ачкычы катары.

9) Жүктү башкаруу жана чектөө

Жогорку чеги 'limit', мисалы, 200.
Server-side backpressure: суроо-убакыт> budget болсо, жооп 'limit' кыскартуу (жана так кардарга чыныгы бет өлчөмүн билдирүүгө).
Rate limits/token/tenant.
Timeout/Retry: экспоненциалдык тыныгуу, демпотенттик кайра суроо.

10) UX аспектилери

Scroll vs номерлөө: чексиз жылдыруу → курсор; саны барактар → offset (бирок маалыматтарды жаңыртуу учурунда так эместигин түшүндүрүп).
"Жерге кайтуу" баскычы: кардардын курсорлорунун стегин сактаңыз.
Бош беттер: эгер 'has _ more = false' болсо, "Дагы" баскычын көрсөтпөңүз.
Туруктуу чек: ал арзан болсо гана так 'total' көрсөтүү (башкача - болжолдуу 'approx _ total').

11) Тестирлөө жана edge учурларда

Чек-баракчалар:
  • Туруктуу сорттоо: ошол эле 'ts' бар элементтер "жарк этпейт".
  • Кошумчалар/өчүрүүлөр: барактардын кесилишинде кайталоолор пайда болбойт.
  • Барактардын ортосундагы чыпкалардын өзгөрүшү: токен "эскирген/шайкеш келбеген" деп четке кагылышы керек.
  • TTL токен: туура ката мөөнөтү бүткөндөн кийин.
  • Чоң тереңдик: жашыруун сызыктуу өсөт.
  • Multishard: туура өлчөө тартиби, starvation "жай" Чард жоктугу.
property-based сыноо мисал (psevdocode):
python
Generate N entries with random inserts between calls
Verify that all pages are merged = = whole ordered fetch

12) Байкоо жана SLO

Метрикасы:
  • 'list _ request _ latency _ ms' (P50/P95/P99) барактын узундугу боюнча.
  • 'seek _ index _ hit _ ratio' (жабуучу индекс боюнча кеткен суроо-талаптардын үлүшү).
  • 'next _ cursor _ invalid _ rate' (валидация каталары/TTL/кол тамгалар).
  • 'merge _ fanout' (баракка тартылган шардалардын саны).
  • 'duplicates _ on _ boundary' жана 'gaps _ on _ boundary' (кардар телеметриясындагы детал).
Логи/соода:
  • Логдордо 'cursor _ id' менен байланышып, payload маскасын.
  • Тегдер: 'page _ size', 'source _ shards', 'db _ index _ used'.
SLO-мисал:
  • Жеткиликтүү: 99. 9% боюнча 'List' ыкмалары.
  • Латенттүүлүк: P95 <200 ms үчүн 'page _ size <= 50' жергиликтүү чардда.
  • Токендин катасы: <0. чалуулардын жалпы санынын 1%.

13) Миграция жана шайкештик

Токенге 'v' киргизип, N жуманын эски версияларын сактаңыз.
сорттоо ачкычтарын өзгөртүп жатканда - "жумшак" ката жөнөтүү '409 Conflict' курьерсиз жаңы листингди аткаруу үчүн.
Каргашалуу окуя (бардык токендердин жылышы): '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/tenant/roles' жазыңыз жана валидация учурунда текшериңиз).
Токендердин хешилерин гана логин.

16) Тез-тез каталар жана анти-үлгүлөрү

Base64 (id) курсор катары: жасалмалоо/алуу оңой, сорттоо өзгөргөндө келишимди бузат.
tie-breaker жоктугу: 'ORDER BY ts DESC' no 'id' → дубликаттар/ат чабуулар.
Токендин майыптыгы жок беттердин ортосундагы фильтрлерди алмаштыруу.
Deep OFFSET: жай жана күтүүсүз.
нускасы жана TTL жок токендер.

17) Mini текшерүү киргизүү

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: мисалы, 'OFFSET/LIMIT' + кэш; жалпы болжолдуу экенин билдириңиз.
тасмалар, аналитика, терең тизмелери, жогорку RPS: гана cursor/seek.
Charded/бөлүштүрүлгөн чогултуу: per-shard cursors + merge токен.
Агымдар/CDC: offsets/ts сыяктуу курсорлор кайра.

19) Мисалы келишим API (резюме)

`GET /v1/items? limit=50&cursor=...`

Жооп ар дайым 'page камтыйт. limit`, `page. has_more', кошумча 'page. next_cursor`.
Курсор тунук эмес, кол коюлган, TTL менен.
сорттоо аныкталган: 'ORDER BY created_at DESC, id DESC'.
Терүү өзгөргөндө жүрүм-турум: элементтер курсорго карата "артка кайтпайт".
Көрсөткүчтөр жана каталар стандартташтырылган: 'invalid _ cursor', 'expired _ cursor', 'mismatch _ filters'.

Бул макала архитектуралык принциптерди жана даяр үлгүлөрдү берет, ал тургай чоң маалыматтар, шардана жана активдүү өзгөрүп турган жазуулар топтомунун шарттарында да тез, алдын ала жана коопсуз бойдон калууда.

Contact

Биз менен байланышыңыз

Кандай гана суроо же колдоо керек болбосун — бизге кайрылыңыз.Биз дайым жардам берүүгө даярбыз!

Интеграцияны баштоо

Email — милдеттүү. Telegram же WhatsApp — каалооңузга жараша.

Атыңыз милдеттүү эмес
Email милдеттүү эмес
Тема милдеттүү эмес
Билдирүү милдеттүү эмес
Telegram милдеттүү эмес
@
Эгер Telegram көрсөтсөңүз — Emailден тышкары ошол жактан да жооп беребиз.
WhatsApp милдеттүү эмес
Формат: өлкөнүн коду жана номер (мисалы, +996XXXXXXXXX).

Түшүрүү баскычын басуу менен сиз маалыматтарыңыздын иштетилишине макул болосуз.