Jeden zapisovatel, mnoho čtenářů
Do repliky zapisuje jediný proces. Není to omezení kapacity — příjem je levný a rejstřík publikuje jeden proud. Je to způsob, jak se vyhnout celé třídě problémů, které by jinak bylo nutné řešit zámky, verzemi a slučováním.
- Vlastnictví feedu
- právě jeden poller, lease v Redisu s TTL
- Výchozí TTL leasu
- 900 sekund
- Výchozí perioda pollu
- 600 sekund, nejvýš 20 dávek na tik
- Čtenáři
- API, UI, exporty a analytika čtou projekci, nikdy repliku přímo
- Stav
- plánováno (fáze 1: poller s leasem)
Co by dva zapisovatelé rozbili
Dva pollery by závodily o checkpoint a duplikovaly práci. Idempotentní zápis podle ID akce by sice zabránil duplicitám v datech, ale ne plýtvání: každý zbytečný požadavek ubírá z denního rozpočtu 3000 požadavků, který je zároveň stropem rychlosti backfillu.
S jedním zapisovatelem jsou záruky uspořádání triviální. Akce se zapisují v pořadí, ve kterém je zdroj publikoval, a nikdo se nemusí ptát, čí verze checkpointu je ta správná.
Lease s TTL, ne zámek navěky
Vlastnictví je časově omezené. Poller, který zemře, lease neuvolní — ten po TTL prostě vyprší a převezme ho jiný. Tím se systém obejde bez ručního odemykání po incidentu.
Poller, který lease nezíská, končí. Nečeká ve frontě a nezkouší to obcházet; příští tik je za pár minut a nic se mezitím neztratí, protože checkpoint drží pozici.
%% title: Jeden zapisovatel díky leasu s TTL %% caption: Poller, který lease nezíská, končí a nečeká. Poller, který zemře, lease neuvolní — ten po TTL vyprší a převezme ho jiný. Checkpoint mezitím drží pozici. sequenceDiagram autonumber participant A as Poller A participant R as Redis lease (TTL 900 s) participant B as Poller B participant DB as Replika + checkpoint A->>R: získat lease R-->>A: přiděleno B->>R: získat lease R-->>B: drží jiný — konec tiku A->>DB: zápis akcí + posun checkpointu (1 transakce) Note over A: pád procesu Note over R: lease po TTL vyprší B->>R: získat lease (další tik) R-->>B: přiděleno B->>DB: pokračuje od checkpointu
Škálování je otázka na straně čtenářů
Zátěž roste s dotazy nad projekcí, ne s příjmem. Čtenářů může být libovolně mnoho a přidat je neznamená sáhnout na zápisovou cestu.
Zapínání feedu je navíc stupňovité: nejdřív jen příjem, pak projekce a teprve nakonec čtecí API. Chyba v projekci se tak najde ve chvíli, kdy projekci ještě nikdo nečte.
Kde to v repozitáři žije
docs/INGESTION.md— invarianty příjmu, jeden vlastník feedu, chování checkpointusrc/progresus_isir/config.py— TTL leasu, perioda pollu, limity dávek a fáze zapínánídocs/runbooks/feed-rollout.md— stupňovité zapínání feedu od příjmu po čtecí API
Souvisí
Event sourcing, protože zdroj je event stream
Systém je konzumentem oficiálního proudu událostí. Z něj staví lokální append-only repliku a z ní přehrává projekci aktuálního stavu. Oprava chyby v interpretaci znamená přehrát log, ne znovu stahovat rejstřík.
Detail
Chování při selhání
Selhání zdroje, pád uprostřed dávky ani nejistá extrakce nesmí skončit zápisem nesprávného stavu. Každý z těchto případů má předem určené chování a žádné z nich se nepřevádí na negativní výsledek.
Detail
Klient WS ISIR a limity
DostupnéKlient k IsirWsPublicService, typované parsování akcí a fail-closed mapování chybových stavů. Rozpočet 50/min a 3000/den je sdílený všemi procesy přes Redis a kontroluje se před každým pokusem; jistič je sdílený a po prodlevě pustí jediný zkušební požadavek. Když Redis neodpovídá, požadavek se neodešle.
Detail