Storh
Записи с приоритет на файловете за PHP: документи JSONC, сегментирани логове само с добавяне и опашки, базирани на логове, с идентификатори UUIDv7.
composer require storh/storhПоследна версия v0.5.2 MIT PHP 8.2+
$pages = $docs
->query()
->where('kind')->eq('page')
->orderBy('title')
->limit(20)
->get();На практика
Бързото начало в две части: документ в основната директория за съхранение, а до него – запис в лог и задача в опашка.
Една основна директория, три енджина
StorageRoot::resolve() нормализира базовата директория и пространството от имена до основна директория, а при първа употреба всеки енджин създава собствена директория в нея.
Всеки енджин връща обекти StorageRecord с id() и data(). Опашката добавя всяко поемане и приключване към своя лог на събитията.
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());
}Хранилище за документи JSONC
Един файл JSONC за запис, идентификатори UUIDv7, шардиране по два символа от последната група на UUID, атомарна подмяна и поточни филтри по полета.
Сегментиран лог
Сегменти само с добавяне от редове JSON с префикси за дължина и контролна сума, разредени индекси, четене по курсор и времеви диапазон, възстановяване след срив и компактиране.
Опашка с лог
Задачите преминават през състоянията чакаща, обработва се и завършена чрез компактни събития в опашка само с добавяне.
Записи UUIDv7
Сортирани идентификатори, адресируеми по време, за стабилни курсори, ограничени обхождания и пътища за съхранение, подходящи за шардиране.
Атомарни записи
Записването във временен файл и атомарното преименуване запазват целостта на записите. След срив на процеса за запис следващото отваряне почиства изоставените временни файлове.
Възстановяване при непълен запис
При четене на сегменти се валидират полетата за дължина и контролна сума; възстановяването отрязва частичните крайни редове.
Файлов приоритет
Без сървър за база данни, без адаптер за рамка, без пакети за изпълнение Composer; подава се директория.
Четене JSONC
Файловете със записи може да съдържат коментари и крайни запетаи. Записите storh са компактни и на един ред JSON, затова коментарите остават до следващото записване.
Конструктор на заявки
Изразителни заявки като where('status')->in([...]) в DocStore и SegmentedLog; DocStore използва вторични индекси, когато има такива.
Вторични индекси
Индекси за равенство, уникалност и диапазон, съхранявани като файлове до колекцията, извлечени от записите и възстановими по всяко време.
Схеми
Незадължителните схеми на колекция валидират всяко записване и указват кои полета да се индексират.
SQL Огледало
Изпращайте колекции към SQLite или MySQL за съединения, търсене и отчети, като файловете остават каноничният източник. Необходим е ext-pdo или ext-mysqli само при използване.
Защо Storh
Директория, не сървър
Подавате базова директория и storh записва там. Необходими са PHP 8.2 и ext-json, без пакети за изпълнение Composer и без адаптер за рамка.
Една форма на запис, три разположения
Документите, логовете и опашките съхраняват идентификатор UUIDv7 и масив с данни. Изберете разположението на диска според натоварването и дръжте и трите под една основна директория.
Проверки, които можете да изпълните
verify() проверява индексите и състоянието на логовете спрямо пълно обхождане на файловете. repair() поставя повредените записи под карантина и отрязва непълните краища на логовете, а CLI извежда JSON за задачи cron и проверки на състоянието.
Бенчмаркове с описана конфигурация
README публикува медианите за 50,000 записа на енджин на Apple M1 Pro с PHP 8.5, например 5.6 µs за четене на отделен запис. При всяко записване в тези измервания се изпълнява fsync, затова скоростта на запис зависи от файловата система.
Сравнение с
storh е файлово хранилище, а не релационен енджин за заявки, затова тези инструменти вършат някои задачи, които то не покрива.
| Инструмент | Подходящ за | Разлики спрямо Storh |
|---|---|---|
| SQLite | Подходящ заСамостоятелен енджин SQL в един файл със сериализируеми ACID транзакции, които издържат при срив на програмата или прекъсване на захранването. Документацията му го представя като заместител на специално създадени файлове с данни. | Разлики спрямо Storhstorh съхранява всеки запис в отделен файл JSON, а ядрото му не изисква PDO драйвер. Не поддържа транзакции с няколко записа; документацията насочва тази работа към истинска база данни. Може да изпраща колекции към SQLite за съединения и отчети, като файловете остават каноничният източник. |
| MySQL | Подходящ заРелационна база данни, обслужвана от многопоточен сървър SQL, с клиентски програми и библиотеки, инструменти за администриране и широк набор от API. | Разлики спрямо Storhstorh работи в процеса PHP с директория, така че няма сървър за поддръжка. За съединения, търсене и отчети копира колекциите в MySQL, включително чрез съществуваща mysqli връзка, а файловете остават основният източник на данни. |
| SleekDB | Подходящ заДокументна база данни с плоски файлове в PHP, без зависимости от трети страни, която съхранява данни без схема като обикновени файлове JSON. Езикът ѝ за заявки API включва съединения, текстово търсене, групиране и филтриране на вложени свойства. | Разлики спрямо Storhstorh съчетава хранилището си за документи със сегментиран лог само с добавяне и опашка, базирана на лог, под една основна директория, като изпълнява fsync за всяко записване, преди да потвърди съхранението му. Съединенията не са част от storh; за тях колекциите се изпращат към SQLite или MySQL. |
Въпроси и отговори
Кратки отговори от документацията на Storh.
Да. DocStore сериализира промените чрез заключване на ниво колекция, а при едновременни записи на един и същ идентификатор печели последното преименуване. Поемането на задачи заключва опашката, така че два работника не могат да поемат една и съща чакаща задача.
Да. При четене се приемат коментари и крайни запетаи, но следващото put() към този идентификатор презаписва файла като компактен JSON и ги премахва. При режим на кеша TRUST не се засичат промени във файлове, направени извън storh.
Четенето по идентификатор остава бързо, докато файловата система може да обработва броя файлове. Сканирането на полета в DocStore без индекс се забавя при над приблизително 10k записа, затова декларирайте индекси за полетата, по които филтрирате. Сканирането и четенето по диапазон в сегментиран лог се справят добре с приблизително 1M записа.
Записите се синхронизират с диска чрез fsync и се публикуват с атомарно преименуване; при повторно отваряне на лог или опашка непълните краища се отрязват до последното потвърдено събитие. Устойчивостта при прекъсване на захранването все пак зависи от това дали файловата система и опциите за монтиране спазват тези синхронизации.
Не. Изпращайте колекциите към SQLite или MySQL чрез SqlMirror за съединения, търсене и отчети. Атомарните записи на няколко записа остават задача за истинска база данни, която е основният източник на данни.
Не. Queue не е универсално хранилище за записи и полезният товар на задачата се изтрива след приключването ѝ.
Започнете с бързото начало, после използвайте „Избор на енджин“, за да съобразите DocStore, SegmentedLog или Queue с натоварването си.