Перейти к содержимому

Storh

Хранилище записей на основе файлов для PHP: документы JSONC, сегментированные журналы только для добавления и очереди на основе журналов с идентификаторами UUIDv7.

Терминал
composer require storh/storh

Последний выпуск v0.5.2 MIT PHP 8.2+

На практике

Краткое руководство состоит из двух частей: документ в корневом каталоге хранилища, затем запись журнала и задание очереди рядом с ним.

Один корневой каталог, три движка

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());

Хранилище документов 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, SegmentedLog или Queue под свою задачу.