Dzinēji
Dzinēja izvēle
Visi trīs dzinēji glabā vienu un to pašu: UUIDv7 ID un datu masīvu, taču diskā tie izkārto datus atšķirīgi. Šis izkārtojums nosaka, kam katrs dzinējs ir piemērots:
| DocStore | SegmentedLog | Queue | |
|---|---|---|---|
| Diskā | viens JSONC fails katram ierakstam, sadalīts mapēs pēc UUID astes | tikai papildināmi segmenti ar garuma un kontrolsummas prefiksu JSON rindām, kā arī manifests | viens tikai papildināms notikumu žurnāls |
| Rakstīšana | atomiska faila aizstāšana katram ierakstam | papildinājumi ar kontrolsummu; pārrakstīšana un dzēšana pievieno jaunus ierakstus, kurus vēlāk atbrīvo compact() |
katra rindas notikuma papildināšana ar kontrolsummu |
| Lasīšana | get() pēc ID, indeksēti vaicājumi |
kursora un laika diapazona skenēšana, get(), izmantojot stāvokļa indeksu |
claim() ievietošanas secībā |
| Piemērotākais lietojums | atsevišķu ierakstu nolasīšana un indeksēti meklējumi jebkura lieluma kolekcijā | papildināšanai intensīvas plūsmas līdz aptuveni 1M ierakstu | noturīga uzdevumu nodošana starp procesiem |
| Ierobežojumi | neindeksētu lauku skenēšana, ja ir vairāk nekā aptuveni 10k ierakstu | bieža atsevišķu ierakstu pārrakstīšana (vecās versijas aizņem vietu līdz saspiešanai) | nav vispārīga ierakstu krātuve; dati tiek dzēsti pēc uzdevuma pabeigšanas |
DocStore un SegmentedLog izmanto vienu un to pašu plūstošo vaicājuma API: viena un tā pati where() ķēde darbojas abos dzinējos, un atšķiras tikai izpilde. DocStore var atbildēt no sekundārajiem indeksiem, bet SegmentedLog filtrē, skenējot segmentus. Queue balstās uz pieprasījumiem, un tajā nav vaicājumu: darbinieki claim() nākamo uzdevumu, nevis filtrē uzdevumus.
Īkšķa likumi:
- Ieraksti, ko izgūstat, atjaunināt vai dzēšat atsevišķi un vaicājat pēc lauka:
DocStore. Pievienojiet indeksus laukiem, pēc kuriem filtrējat. - Notikumi vai versijas, ko galvenokārt pievienojat un lasāt secīgi vai noteiktā laika posmā:
SegmentedLog. - Uzdevumi, ko ražotāji nodod darbinieku procesiem:
Queue. Pieprasījumi un pabeigšana ir droši vairākiem procesiem, betclaimMany()/completeMany()ļauj sadalīt slēdzeņu un fsync izmaksas. - Savienojumi, meklēšana vai atskaites par jebkuru kolekciju: pievienojiet SQL spoguli. Faili paliek kanoniski; spogulis ir atjaunojama projekcija SQLite vai MySQL.
Dzinēji ir kombinējami: tiem kopīga ir tikai saknes direktorija, tāpēc viena lietotne vienā krātuves saknē var glabāt saturu DocStore, audita žurnālu SegmentedLog un fona uzdevumus Queue.
DocStore
DocStore paredzēts atsevišķu noturīgu ierakstu nolasīšanai un vienkāršai skenēšanai. Tas katram ierakstam raksta atsevišķu JSONC failu:
$store = new Storh\DocStore($root, 'articles');
$record = $store->put(['slug' => 'hello', 'published' => true]);
$same = $store->get($record->id());
Ierakstu faili tiek sadalīti mapēs pēc pēdējām UUID rakstzīmēm, lai UUIDv7 rakstīšanas slodze sadalītos pa direktorijām:
articles/data/2d/018bcfe5-6800-7000-8000-2d5dba6274da.jsonc
SegmentedLog
SegmentedLog paredzēts ierakstiem, ko bieži papildina, kursora nolasīšanai un laika diapazonu nolasīšanai. Ieraksti tiek rakstīti aktīvajā segmentā — katrs ieraksts atsevišķā rindā formā <byte-length>\t<xxh32>\t<json> (skatiet Atomiškums). Segmentu failiem ir paplašinājums .ndjson, taču garuma un kontrolsummas prefiksa dēļ parastie NDJSON rīki tos nevar nolasīt; izmantojiet stream() vai vaicājumu veidotāju, lai nolasītu ierakstus. Pilnie segmenti tiek noslēgti un aizstāti ar aizzīmogotiem segmentiem, kuriem ir reti indeksi.
$events = new Storh\SegmentedLog($root, 'events');
$events->put(['type' => 'user.created']);
$events->compact();
Rinda
Queue paredzēts augstas veiktspējas noturīgām darbu rindām. Ievietošana rindā, pieprasīšana, pabeigšana, atkārtota ievietošana un notīrīšana ieraksta tikai papildināmus notikumus queue.log; rindas stāvoklis tiek atskaņots atmiņā, to atverot. Pakešu metodes sadala slēdzeņu un iztukšošanas izmaksas starp daudziem uzdevumiem. Žurnāls pieaug ar katru notikumu; stats() ziņo par tā pašreizējo izmēru baitos.
$queue = new Storh\Queue($root, 'mail');
$queue->enqueue(['to' => 'person@example.test']);
$job = $queue->claim();
Izturība un vienlaicīga piekļuve
storh publicē failu ierakstus, veicot atomisku pārdēvēšanu mērķa direktorijā. Atkārtota atvēršana un repair() noņem pamestos pagaidu failus, kuru īpašnieka process vairs nedarbojas, bet atstāj neskartus aktīvo rakstītāju pagaidu failus. Rakstītāju marķieri ļauj šo pārbaudi veikt nemainīgā laikā, tāpēc pēc avārijas kolekcija tiek pārskatīta, atverot krātuvi.
SegmentedLog un Queue raksta žurnāla rindas, kuru garumu un kontrolsummu pārbauda. Atkārtoti atverot vai labojot, nepilnīgās beigu rindas tiek saīsinātas līdz pēdējam apstiprinātajam notikumam, un stāvoklis atmiņā tiek atjaunots no noturīgā žurnāla satura. Žurnāla un rindas ierakstīšana tiek serializēta ar failu sistēmas slēdzenēm.
DocStore izmaiņas tiek serializētas ar kolekcijas līmeņa rakstīšanas slēdzeni, tāpēc ierakstu faili un sekundārie indeksi tiek atjaunināti vienas saskaņotības robežas ietvaros vairākos procesos. Vienlaicīga rakstīšana atšķirīgos ierakstu ID ir droša, ja tiek ievēroti tie paši pieņēmumi par failu sistēmas atomisko pārdēvēšanu. Vienlaicīgas rakstīšanas gadījumā vienam ID uzvar pēdējā pārdēvēšana.
storh iztukšo un sinhronizē failu deskriptorus pirms pārdēvēšanas vai papildināšanas pabeigšanas un pēc atomiskas pārdēvēšanas mēģina sinhronizēt vecākdirektorijas. Izturība pret strāvas zudumu joprojām ir atkarīga no tā, vai pamatā esošā failu sistēma un montēšanas opcijas ievēro šīs sinhronizācijas.