Storh
Rekordy oparte na plikach dla PHP: dokumenty JSONC, segmentowe dzienniki tylko do dopisywania oraz kolejki oparte na dziennikach z identyfikatorami UUIDv7.
composer require storh/storhNajnowsze wydanie v0.5.2 MIT PHP 8.2+
$pages = $docs
->query()
->where('kind')->eq('page')
->orderBy('title')
->limit(20)
->get();W praktyce
Szybki start w dwóch częściach: dokument w głównym katalogu magazynu, a obok wpis w logu i zadanie w kolejce.
Jeden katalog główny, trzy silniki
StorageRoot::resolve() normalizuje katalog bazowy i przestrzeń nazw, tworząc katalog główny, a każdy silnik przy pierwszym użyciu tworzy w nim własny katalog.
Każdy silnik zwraca obiekty StorageRecord z id() i data(). Kolejka dopisuje każde przejęcie i ukończenie zadania do swojego logu zdarzeń.
use Storh\DocStore;
use Storh\Queue;
use Storh\RecordQuery;
use Storh\SegmentedLog;
use Storh\StorageRoot;
$root = StorageRoot::resolve(__DIR__ . '/var/storh', 'demo');
$docs = new DocStore($root, 'pages');
$home = $docs->put([
'kind' => 'page',
'title' => 'Home',
]);
$loaded = $docs->get($home->id());$log = new SegmentedLog($root, 'events');
$log->put([
'type' => 'page.saved',
'pageId' => $home->id(),
]);
foreach ($log->stream(RecordQuery::all()->after($home->id())->limit(50)) as $record) {
// Process records lazily.
}
$queue = new Queue($root, 'jobs');
$jobId = $queue->enqueue(['task' => 'render', 'pageId' => $home->id()]);
$job = $queue->claim();
if (null !== $job) {
$queue->complete($job->id());
}Magazyn dokumentów JSONC
Jeden plik JSONC na rekord, identyfikatory UUIDv7, partycjonowanie według dwóch znaków z ostatniej grupy UUID, atomowa podmiana i strumieniowe filtry pól.
Dziennik segmentowy
Segmenty dopisywane wyłącznie na końcu, z wierszami poprzedzonymi długością i sumą kontrolną JSON, rzadkimi indeksami, odczytem według kursora i zakresu czasu, odzyskiwaniem po awarii oraz kompaktowaniem.
Kolejka logów
Zadania przechodzą przez stany oczekujące, przetwarzane i ukończone przy użyciu zwięzłych zdarzeń dopisywanych do kolejki.
Rekordy UUIDv7
Sortowalne identyfikatory adresowalne czasowo, zapewniające stabilne kursory, ograniczone skanowanie i przyjazne shardom ścieżki przechowywania.
Zapisy atomowe
Zapisy do plików tymczasowych i atomowe zmiany nazw zapewniają spójność rekordów. Po awarii procesu zapisującego przy kolejnym otwarciu usuwane są osierocone pliki tymczasowe.
Odzyskiwanie po niepełnym zapisie
Odczyt segmentów weryfikuje pola długości i sumy kontrolnej; odzyskiwanie skraca plik, usuwając niepełne końcowe wiersze.
Najpierw pliki
Bez serwera bazy danych, adaptera frameworka i pakietów uruchomieniowych Composer; wywołujący przekazuje katalog.
Odczytuje JSONC
Pliki rekordów mogą zawierać komentarze i końcowe przecinki. Zapis storh tworzy zwięzły, jednoliniowy JSON, więc komentarze pozostają do następnego zapisu.
Konstruktor zapytań
Łańcuchowe zapytania, takie jak where('status')->in([...]) w DocStore i SegmentedLog; DocStore korzysta z indeksów pomocniczych, jeśli są dostępne.
Indeksy pomocnicze
Indeksy równości, unikalności i zakresów przechowywane jako pliki obok kolekcji, wyprowadzane z rekordów i możliwe do odbudowania w dowolnym momencie.
Schematy
Opcjonalne schematy kolekcji weryfikują każdy zapis i określają, które pola mają być indeksowane.
SQL Mirror
Przesyłaj kolekcje do SQLite lub MySQL, aby wykonywać złączenia, wyszukiwanie i raportowanie, zachowując pliki jako źródło prawdy. Wymaga ext-pdo lub ext-mysqli tylko przy użyciu tej funkcji.
Dlaczego Storh
Katalog, nie serwer
Przekazujesz katalog bazowy, a storh zapisuje w nim dane. Wymaga PHP 8.2 i ext-json, bez pakietów uruchomieniowych Composer ani adaptera frameworka.
Jeden kształt rekordu, trzy układy
Dokumenty, logi i kolejki przechowują identyfikator UUIDv7 oraz tablicę danych. Wybierz układ na dysku odpowiedni do obciążenia i trzymaj wszystkie trzy w jednym katalogu głównym.
Kontrole, które możesz uruchomić
verify() sprawdza indeksy i stan logów, porównując je z pełnym skanem plików. repair() poddaje kwarantannie uszkodzone rekordy i skraca niepełne końcówki logów, a CLI wyświetla JSON dla zadań cron i kontroli stanu.
Testy wydajności z opisem konfiguracji
README publikuje mediany dla 50,000 rekordów na silnik na komputerze Apple M1 Pro z PHP 8.5, na przykład 5.6 µs na odczyt punktowy. Każdy zapis w tych testach jest synchronizowany przez fsync, więc szybkość zapisów zależy od systemu plików.
W porównaniu z
storh to magazyn oparty na plikach, a nie relacyjny silnik zapytań, dlatego te narzędzia wykonują część zadań, których on nie obsługuje.
| Narzędzie | Dobre w | Różnica w porównaniu z Storh |
|---|---|---|
| SQLite | Dobre wSamodzielny silnik SQL w jednym pliku, z serializowalnymi transakcjami ACID, które zachowują spójność po awarii programu lub utracie zasilania. Dokumentacja przedstawia go jako zamiennik doraźnie tworzonych plików danych. | Różnica w porównaniu z Storhstorh przechowuje osobny plik JSON dla każdego rekordu, a jego rdzeń nie wymaga sterownika PDO. Nie obsługuje transakcji obejmujących wiele rekordów; dokumentacja zaleca użycie do tego celu prawdziwej bazy danych. Może przesyłać kolekcje do SQLite w celu wykonywania złączeń i raportowania, zachowując pliki jako źródło prawdy. |
| MySQL | Dobre wRelacyjna baza danych obsługiwana przez wielowątkowy serwer SQL, z programami i bibliotekami klienckimi, narzędziami administracyjnymi oraz szerokim wyborem interfejsów API. | Różnica w porównaniu z Storhstorh działa w procesie PHP i korzysta z katalogu, więc nie trzeba obsługiwać serwera. Na potrzeby złączeń, wyszukiwania i raportowania kopiuje kolekcje do MySQL, również za pośrednictwem istniejącego uchwytu mysqli; pliki pozostają źródłem prawdy. |
| SleekDB | Dobre wDokumentowa baza danych oparta na plikach w PHP, bez zależności od firm trzecich, przechowująca dane bez schematu jako zwykłe pliki JSON. Jej język zapytań API obsługuje złączenia, wyszukiwanie tekstowe, grupowanie i filtrowanie przez having oraz filtrowanie według zagnieżdżonych właściwości. | Różnica w porównaniu z Storhstorh łączy magazyn dokumentów z segmentowanym logiem dopisywanym wyłącznie na końcu i kolejką opartą na logu, umieszczając je pod jednym katalogiem głównym, a każdy zapis synchronizuje przez fsync przed potwierdzeniem jego zapisania. Złączenia nie są częścią storh; w tym celu przesyła kolekcje do SQLite lub MySQL. |
Pytania i odpowiedzi
Krótkie odpowiedzi z dokumentacji Storh.
Tak. DocStore szereguje modyfikacje za pomocą blokady zapisu na poziomie kolekcji, a przy równoczesnych zapisach tego samego identyfikatora wygrywa ostatnia zmiana nazwy. Przejęcie zadania przez kolejkę utrzymuje blokadę kolejki, więc dwóch pracowników nie przejmie tego samego oczekującego zadania.
Tak. Odczyt akceptuje komentarze i końcowe przecinki, ale następny zapis put() dla tego identyfikatora przepisuje plik w zwięzłym formacie JSON, usuwając je. W trybie pamięci podręcznej TRUST zmiany plików wprowadzone poza storh nie są wykrywane.
Odczyty punktowe według identyfikatora pozostają szybkie, dopóki system plików obsługuje daną liczbę plików. Skanowanie pól DocStore bez indeksu zwalnia przy około 10k rekordów, dlatego dodaj indeksy dla filtrowanych pól. Skanowanie segmentowanych logów i odczyty zakresów sprawdzają się przy około 1M rekordów.
Zapisy są synchronizowane przez fsync i publikowane za pomocą atomowej zmiany nazwy, a ponowne otwarcie logu lub kolejki skraca niepełne końcówki do ostatniego zatwierdzonego zdarzenia. Trwałość danych po utracie zasilania nadal zależy od tego, czy system plików i opcje montowania przestrzegają tych synchronizacji.
Nie. Przesyłaj kolekcje do SQLite lub MySQL za pomocą SqlMirror, aby wykonywać złączenia, wyszukiwanie i raportowanie. Atomowe zapisy wielu rekordów nadal należy powierzyć prawdziwej bazie danych pełniącej rolę systemu ewidencji.
Nie. Queue nie jest ogólnym magazynem rekordów, a dane zadania są usuwane po jego ukończeniu.
Zacznij od szybkiego startu, a następnie skorzystaj z sekcji Wybór silnika, aby dopasować DocStore, SegmentedLog lub Queue do swojego obciążenia.