<h3> <b>futriix — легковесная распределённая in-memory СУБД на Go без блокировок с поддержкой Lua‑плагинов,оптимизированная для систем семейства Linux/Illumos/OpenIndiana/Solaris)</b> <br></h3>
> **ALPHA VERSION**<br><br>**Проект достаточно стабилен в тестовых сценариях, но категорически не рекомендуется для промышленного использования до выхода версии 3.0.**
>
> **Мы открыты для предложений, и очень признательны за обратную связь!**
futriix — это лёгкая распределённая NoSQL‑СУБД на Go с MongoDB‑совместимым интерфейсом. Работает в памяти (in‑memory), использует неблокирующие структуры (wait‑free и lock‑free) и алгоритм консенсуса Raft — что даёт предсказуемую производительность под высокой нагрузкой.<br>
Это HTAP‑система: сочетает OLTP (Batch-команды вместо ACID‑транзакций) и OLAP (через индексы, триггеры, Lua‑плагины и аналитические функции) — можно обрабатывать и анализировать данные почти в реальном времени. <br>
В основе управления данными лежат — временные метки: они обеспечивают версионирование записей и упорядочивание событий в распределённой среде. Это позволяет точно отслеживать изменения, гарантировать согласованность данных между узлами и корректно разрешать конфликты при параллельных обновлениях. <br>
> 1. **Быстрое прототипирование и R&D**- Ситуация, в которой нужно быстро проверить гипотезу или сделать рабочий прототип. Забудьте о блокировках и жёстких схемах — просто кладите документы и меняйте структуру когда угодно, без лишних настроек.<br>
> 2. **Встраиваемое хранилище для десктоп-приложений**- Ситуация, в которой нужно быстро разработать приложение для компьютера. Получите готовое распределённое хранилище, которое работает прямо внутри вашей программы, а не как отдельный сервер — легко встраивается и работает «из коробки».
> 3. **Обработка и хранения метрик**- Ситуация, когда нужно собирать, сохранять и быстро обрабатывать потоки метрик.
> 4. **edge-сценарии как часть распределённой системы**-Ситуация, когда на цифровой периферии (edge) требуется автономное, отказоустойчивое
> хранилище.<br>
> Futriix позволяет развернуть лёгкий узел в любом месте, в том числе в Закрытой Программной Среде (ЗПС) — изолированном контуре, где критичны
> безопасность и контролируемое исполнение. Узел работает без постоянного соединения с центром, синхронизируется асинхронно и автоматически
> интегрируется в любую общую распределённую сеть. За счёт совместимости с MongoDB упрощается унификация данных между центром и периферией.
Проект распространяется под лицензией **`CDDL 1.0`**. Подробнсти в файлах `LICENSE`.
Эта лицензия позволяет вам производить копирование, модификацию, распространение, включение в другие проекты, получение патентных прав, распространение бинарных файлов с доступом к их исходному коду. Она запрещает вам добавление новых ограничений, скрытие изменений, удаление оригинальных уведомлений, несоблюдение условий CDDL 1.0 при перераспределении, неправильное связывание с другими лицензиями.
Все дополнительное программное обеспечение (включая скрипт компиляции проекта `build.sh`) предоставляются "как есть", без гарантий и обязательств со стороны разработчиков. Разработчики не несут ответственности за прямой или косвенный ущерб, вызванный использованием открытого кода Futriix и futriix или технических решений, использующих этот код.
* **База Данных(БД)** - это структурированное, организованное хранилище данных, которое позволяет удобно собирать, хранить, управлять и извлекать информацию.
* **Мультимодельная СУБД** - это СУБД, которая объединяет в себе поддержку нескольких моделей данных (реляционной, документной, графовой, ключ-значение и др.) в рамках единого интегрированного ядра.
* **Резидентная СУБД** - это СУБД, которая работает непрерывно в оперативной памяти (RAM).
* **Eventual consistency** — модель согласованности в распределённых системах, при которой после прекращения новых обновлений все реплики данных со временем приходят к одинаковому состоянию.
1.**Допускает временные расхождения** <br>В промежутке между записью и завершением репликации разные узлы могут отдавать разные версии одних и тех же данных. Это нормально для модели и закладывается в дизайн. <br>
2.**Асинхронная репликация** <br>Обновления распространяются по узлам без ожидания подтверждения от всех участников — это повышает доступность и снижает задержки, но добавляет окно несогласованности.<br>
3.**Гарантия сходимости**<br> Если новые изменения не поступают, система гарантированно достигает согласованного состояния на всех репликах. Момент, когда это произойдёт, заранее не фиксируется.<br>
4.**Зависимость от механизмов разрешения конфликтов**<br> Поскольку одновременные изменения могут возникать на разных узлах, корректная работа eventual consistency опирается на стратегии разрешения конфликтов (например, по timestamp, векторные часы, last-write-wins с учётом метаданных и т. п.)<br>
***Слайс (Slice-в пер.с англ.слой)**- в терминах субд Futriix имеет два значения:
***1.** Cиноним "база данных"
***2.** Термин пришедший из терминологии суд MongoDB, а именно: Логический и физически изолированный фрагмент коллекции документов, полученный в результате горизонтального партиционирования (шардирования) и размещенный на определенном узле кластера с целью масштабирования производительности и объема данных.
* **Временная метка (time stamp)** - это автоматически фиксируемое значение времени создания, изменения или удаления объекта в СУБД, представленное в формате Unix-миллисекунд (количество миллисекунд, прошедших с 1 января 1970 года) с возможностью отображения в человекочитаемом виде YYYY-MM-DD HH:MM:SS.mmm. Необходима для понимание последовательности операций при сбоях, выявления аномалий в поведении системы,архивация старых записей, отслеживание несанкционированных изменений, автоматический выход из сессий с ограниченным временем действия, Статистика активности за период).
* **Узел (синонимы хост,нода,шард)** - это отдельный сервер (физический или виртуальный), который является частью кластера или распределенной системы и выполняет часть общей работы.
* **Кластер** - это группа компьютеров, объединённых высокоскоростными каналами связи для решения сложных вычислительных задач и представляющая с точки зрения пользователя группу серверов, объединенных для работы как единая система.
* **Репликасет** - это группа серверов СУБД, объединенных в отказоустойчивую конфигурацию, где один узел выполняет роль первичного (принимающего операции записи), а один или несколько других - роль вторичных (синхронизирующих свои данные с первичным и обслуживающих чтение), с автоматическим переизбранием первичного узла в случае его сбоя.
* **OLTP (Online Transactional Processing-Онлайн обработка транзакций)**- это технология обработки транзакций в режиме реального времени. Её основная задача заключается в обеспечении быстрого и надёжного выполнения операций, которые происходят ежесекундно в бизнесе. Они обеспечивают быстрое выполнение операций вставки, обновления и удаления данных, поддерживая целостность и надежность транзакций.
* **OLAP (Online Analytical Processing - Оперативная аналитическая обработка)** — это технология, которая работает с историческими массивами информации, извлекая из них закономерности и производя анализ больших объемов данных, поддерживает многоразмерные запросы и сложные аналитические операции. Данная технология оптимизирована для выполнения сложных запросов и предоставления сводной информации для принятия управленческих решений.
* **HTAP (Hybrid Transactional and Analytical Processing - Гибридная транзакционно-аналитическая обработка)**- это технология, которая заключаются в эффективном совмещении операционных и аналитических запросов, т.е. классов OLTP и OLAP.
* **workflow (англ. workflow — «поток работы»)** — это принцип организации рабочих процессов, в соответствии с которым повторяющиеся задачи представлены как последовательность стандартных шагов.
* **Lock‑free алгоритмы** — это алгоритмы, гарантирующие, что хотя бы один из потоков выполнения продвигается вперёд (завершает операцию) за конечное число шагов, даже если другие потоки задержаны или прерваны. При этом отдельные потоки могут испытывать задержки, но система в целом продолжает прогрессировать.
* **Wait‑free алгоритмы** — это алгоритмы, гарантирующие, что каждый поток завершит свою операцию за заранее ограниченное (конечное) число шагов, независимо от состояния и поведения остальных потоков. Это обеспечивает отсутствие задержек и голода для любого из участников параллельного выполнения.
* **ЗПС (Замкнутая Программная Среда)** - Это локальная сеть предприятия или организации как правило без доступа к сети "Интернет", своего рода "фильтр" содержащий в себе перечень программного обеспечения (ПО), которому разрешено работать на компьютере, в то время как ПО, которого нет в этом списке, будет запрещено к исполнению.
Несмотря на то, что `futriix` сохраняет кроссплатформенную совместимость и полностью поддерживает Linux, в качестве основной целевой платформы выбрана операционная система **Illumos (OpenIndiana)**. Для резидентных (in-memory) NoSQL-СУБД, эксплуатируемых в Замкнутых Программных Средах (ЗПС), ОС общего назначения (такие как Linux) часто вносят недетерминированные задержки (ресурсный джиттер) и обладают избыточным архитектурным оверхедом. Родословная Solaris в Illumos обеспечивает критически важный фундамент, построенный на строгом детерминизме и эталонном системном проектировании.
**Ключевые архитектурные причины приоритета ядра Illumos:**
* **Строгий детерминизм ядра и планирование реального времени:** В отличие от планировщика Linux (CFS/EEVDF), оптимизированного под компромисс между пропускной способностью и интерактивностью, диспетчер задач Illumos гарантирует жесткое и предсказуемое распределение ресурсов процессора. Это исключает внезапные задержки (jitter), критические для wait-free/lock-free алгоритмов обработки транзакций в памяти.
* **Масштабируемые порты событий (`port_create`):** Для организации асинхронного высоконагруженного ввода-вывода `futriix` задействует системный интерфейс Event Ports вместо Linux `epoll`. Архитектурное преимущество портов событий заключается в нативном устранении проблемы «эффекта проснувшегося стада» (thundering herd) на уровне ядра и лучшей локальности процессорного кэша при работе с пулами потоков.
* **Нативная архитектура управления сбоями (FMA):** Эксплуатация СУБД типа in-memory сопряжена с рисками аппаратных сбоев памяти. Подсистема Illumos FMA непрерывно анализирует телеметрию оборудования: если планка оперативной памяти начинает деградировать, FMA изолирует сбойные страницы «на лету» *до* того, как произойдет Kernel Panic, обеспечивая непрерывную доступность СУБД.
* **Эталонная целостность WAL через нативную ZFS:** Сегментированный лог упреждающей записи (WAL) требует абсолютной надежности хранения. В Illumos файловая система ZFS является родной и глубоко интегрирована в слой виртуальной памяти ядра. Она верифицирует блоки данных с помощью криптографических контрольных сумм и автоматически исправляет скрытые повреждения бит (*silent data corruption*), гарантируя надежность (Durability) без потери производительности.
* **Жесткая изоляция на уровне ОС (Zones):** Технология контейнеризации Zones «вшита» непосредственно в ядро системы, в отличие от контейнеров Linux, реализованных в виде надстройки через пространства имен (namespaces) и cgroups. Это обеспечивает чистую, математически строгую логическую и физическую изоляцию распределенных узлов СУБД, запущенных на общем оборудовании.
* **Лицензия CDDL для применения в ЗПС:** Лицензия Common Development and Distribution License (CDDL) позволяет модифицировать и усиливать безопасность ядра ОС под требования отечественных регуляторов без необходимости раскрывать производный код (в отличие от жестких копилефт-требований GPL в Linux). Это радикально упрощает создание доверенных, сертифицированных программно-аппаратных комплексов.
| 1 | **Wait-free операции доступа** | • Чтение: `sync.Map.Load()` — атомарная операция без блокировок<br>• Запись: `sync.Map.Store()` — атомарная замена значения<br>• Удаление: `sync.Map.Delete()` — атомарное удаление | **O(1) амортизированное** | *Амортизированная сложность — средняя стоимость операции в серии операций, даже если отдельные операции могут быть дорогими* |
| 2 | **Поиск по индексу** | **Уникальный индекс:**<br>1. `index.data.Load(value)` → получение ID документа<br>2. `docs.Load(ID)` → возврат документа<br><br>**Неуникальный индекс:**<br>1. `index.data.Range()` → сканирование всех записей<br>2. Сравнение значений с учётом типов (`compareValues`)<br>3. Сбор всех подходящих ID | **Уникальный: O(1)**<br><br>**Неуникальный: O(n)** | `n` — размер индекса |
| 3 | **Batch (атомарная группа операций)** | 1. `NewBatch()` → создание batch<br>2. Добавление операций (`AddInsert`, `AddUpdate`, `AddDelete`, `AddRestore`)<br>3. `Commit()` → запись всего batch в WAL с fsync<br>4. Применение операций к in-memory структурам<br>5. При ошибке — откат (best-effort) | **E[T] = O(M) + O(WAL)** | `M` — количество операций в batch<br>`WAL` — размер журнала |
| 4 | **Валидация ограничений (Constraints)** | Последовательная проверка документа:<br>1. Обязательные поля → проверка наличия<br>2. Минимальные значения (`MinValues`) → сравнение чисел<br>3. Максимальные значения (`MaxValues`) → сравнение чисел<br>4. Regex паттерны → сопоставление строк<br>5. Enum значения → поиск в разрешённом списке | **O(k + m)** | `k` — количество полей в документе<br>`m` — количество ограничений |
| 5 | **Выполнение триггеров** | Для каждого триггера события:<br>1. Проверка `Enabled`<br>2. Оценка условия (`TriggerCondition`)<br>3. Сопоставление оператора с полем документа<br>4. Выполнение действия (`abort`/`skip`/`modify`/`log`)<br>5. Логирование с временной меткой и длительностью | **O(T × (C + O))** | `T` — количество триггеров на событие<br>`C` — количество условий в триггере<br>`O` — количество операций в триггере |
| 6 | **Мягкое удаление** | **SoftDelete:**<br>1. `doc.DeletedAt = now`<br>2. `doc.Version++`<br>3. `docs.Store(id, doc)` — сохранение, не удаление<br>4. `removeFromIndexes(doc)` — исключение из поиска<br><br>**Restore:**<br>1. `doc.DeletedAt = 0`<br>2. `doc.Version++`<br>3. `docs.Store(id, doc)`<br>4. `addToIndexes(doc)` — возврат в индексы | **O(1) + O(K)** | `K` — количество индексов в коллекции |
| 7 | **TTL-очистка** | Фоновый цикл с интервалом `TTL/2` секунды:<br>1. `Scan` всех документов коллекции<br>2. Проверка: `now - doc.CreatedAt > TTL × 1000`<br>3. Добавление просроченных ID в буфер<br>4. Пакетное удаление (с учётом SoftDelete) | **O(N × (1 + K)) + O(D × (1 + K))** | `N` — общее количество документов<br>`K` — количество индексов<br>`D` — количество просроченных документов (`D ≤ N`) |
| 8 | **Сериализация MessagePack** | **Экспорт:**<br>1. Обход всех коллекций БД<br>2. Сбор документов, метаданных, индексов, ограничений<br>3. Добавление экспортных метаданных (время, версия)<br>4. `Marshal` в бинарный формат<br><br>**Импорт:**<br>1. `Unmarshal` из бинарного формата<br>2. Восстановление структуры БД и коллекций<br>3. Сохранение исходных временных меток<br>4. Фиксация метаданных импорта | **O(N × F) + O(C × I)** | `N` — общее количество документов<br>`F` — среднее количество полей в документе<br>`C` — количество коллекций<br>`I` — среднее количество индексов на коллекцию |
| 9 | **Распределённый консенсус (Raft)** | **Кластерные операции:**<br>1. Лидер принимает запрос на запись<br>2. Репликация лога на followers<br>3. Подтверждение от большинства (quorum)<br>4. Коммит и применение к state machine<br>5. Ответ клиенту<br><br>**Выбор лидера:**<br>1. Heartbeat-таймаут<br>2. Переход в состояние candidate<br>3. Запрос голосов (`RequestVote`)<br>4. Получение голосов большинства<br>5. Становление лидером | **Операция записи:**<br>**O(L) + O(R) + O(Commit)**<br><br>**Выбор лидера:**<br>**В среднем: O(R × log N)**<br>**В худшем: O(R × N)** | `L` — размер лога операции<br>`R` — RTT до followers (сетевая задержка)<br>`Commit` — время применения к state machine<br>`N` — количество узлов в кластере |
| 10 | **Работа Lua-плагинов** | **Загрузка:**<br>1. Чтение `.lua` файла<br>2. Создание изолированного Lua-состояния<br>3. Регистрация функций доступа к СУБД<br>4. Выполнение скрипта в защищённом режиме<br>5. Сохранение указателя на состояние<br><br>**Выполнение функции:**<br>1. Поиск функции в глобальном пространстве Lua<br>2. Конвертация Go → Lua значений<br>3. Вызов с защитой от паники<br>4. Измерение времени выполнения<br>5. Конвертация результата Lua → Go<br>6. Логирование события | **Загрузка:**<br>**O(P + C)**<br><br>**Выполнение функции:**<br>**O(convert_args + execution + convert_result)** | `P` — размер файла плагина (байт)<br>`C` — сложность компиляции Lua (обычно O(P))<br>`convert_args = O(N_args × V)`<br>`execution = O(L)` — время выполнения скрипта<br>`convert_result = O(V)`<br>`V` — сложность конвертации значения (зависит от глубины вложенности) |
> **Важно: из‑за архитектурных особенностей (низкоуровневых системных вызовов, специфичных для POSIX‑совместимых ядер) запуск на Windows(включая WSL) и macOS не поддерживается!**
Основным и единственным файлом конфигурации субд futriix является Файл `config.toml`, который используется только при первом запуске кластера для инициализации базовых параметров. Он содержит все настройки СУБД:
Быстрый старт — это краткое руководство для тех, кто хочет сразу попробовать **futriix** в деле. Здесь вы найдёте минимально необходимые команды для установки, запуска и первого взаимодействия с СУБД. Мы намеренно опустили тонкости настройки, чтобы вы могли оценить основные возможности без погружения в документацию. Полный список параметров и режимов работы описан в следующих разделах.</br></br>
В субд **"futriix"** используется два журнала для ведение логов: `"futriix.log"`-основной журнал, в котором ведутся логи при работе в субд через терминал.
**futriix.log** — основной системный журнал, фиксирующий все события жизненного цикла СУБД: запуск/остановку сервера, инициализацию компонентов (batch, Raft-координатор, ACL), состояние кластера и критические ошибки выполнения запросов.
Журнал использует структурированный JSON-формат (для webui.log) и текстовый формат с временными метками (для futriis.log), что обеспечивает удобный парсинг и интеграцию с системами мониторинга.
Журналы автоматически ротируются и ограничены по размеру (по умолчанию 10000 записей для webui.log), предотвращая неконтролируемый рост дискового пространства при длительной работе сервера.
Для проверки корректности функционирования субд на уровне исходного кода, был разработан набор из пяти тестов: (регрессионный, smoke-тест, функциональный, интеграционный и нагрузочный).
Разработанный набор из пяти вышеупомянутых тестов на языке Lua обеспечивает комплексную проверку всех ключевых компонентов СУБД: CRUD-операций, индексов, batch-операций, ограничений целостности, ACL, триггеров, версионирования через WAL, а также взаимодействия API с хранилищем и кластерной координации.
Регрессионный тест гарантирует, что изменения кода не нарушили существующую функциональность, smoke-тест выполняет быструю проверку доступности и базовой работоспособности системы.
Функциональный и интеграционный тесты проверяют корректность реализации бизнес-требований и взаимодействие между компонентами, а нагрузочный тест оценивает производительность (латентность, пропускную способность) под различными сценариями использования.
Вы можете использовать стандартные команды: `insert()`, `find()`, `update()`, `delete()` — точно так же, как в MongoDB.
Все вышеперечисленные CRUD‑операции (создание, чтение, обновление, удаление) выполняются без блокировок (wait‑free) и гарантируют корректную работу при параллельном доступе за счёт атомарных структур данных.
Futriix поддерживает два базовых типов индексов: **первичные (по _id)** и вторичные индексы, хранящиеся отдельно от документов.
Кроме того в субд присутствуют уникальные и составные индексы, поиск по точному значению и префиксу, а также автоматическое обновление индексов при изменениях документов.
В СУБД **futriix** для обеспечения надёжности (durability), атомарности и быстрого восстановления базы данных реализована система журналирования на основе **WAL (Write-Ahead Log)**.
Все мутации — как групповые (batch), так и одиночные (прямые вызовы `Insert`, `Update`, `Delete`, `Restore` из REPL, HTTP-API и Lua-плагинов) — проходят через WAL. Это даёт:
**Batch** — это группа операций, применяемых **атомарно**: либо все операции из группы применяются, либо ни одна. Batch заменяет полноценные ACID-транзакции в локальном узле и работает по принципу «всё или ничего» через WAL.
- **Атомарность** через WAL: сначала весь batch сериализуется и записывается в WAL с `fsync`, только после успешной записи операции применяются к in-memory структурам.
- **Откат при ошибке применения**: если операция падает на середине применения, уже применённые операции откатываются (best-effort) — полная атомарность гарантируется на уровне WAL при восстановлении.
- **Короткое время жизни**: batch создаётся, наполняется операциями и коммитится в рамках одной логической операции. Не поддерживает savepoints, таймауты, распределённую координацию.
- **Реестр активных batch'ей**: `BatchManager.activeBatches` (см. `runtime_limits.go`) защищает документы, участвующие в незакоммиченном batch, от вытеснения (eviction) при нехватке памяти.
**WAL (Write-Ahead Log)** — сегментированный журнал предзаписи, который является **единственным источником истины** для durability. Каждая мутация сначала попадает в WAL, синхронизируется на диск, и только потом применяется к in-memory структурам.
Для **распределённых** операций (между узлами кластера, между сервисами, для долгоживущих бизнес-процессов) используется паттерн **SAGA с оркестратором**:
- Глобальная согласованность достигается через последовательность **компенсируемых локальных шагов**.
- Каждый шаг SAGA может использовать **batch** для гарантии атомарности внутри себя.
- Оркестратор отслеживает состояние шагов, инициирует **компенсацию** при сбоях и гарантирует завершение сценария в согласованном состоянии.
- Состояние SAGA персистентно хранится в JSON-файлах (директория `saga_states/`), при старте pending-шаги восстанавливаются, а просроченные — компенсируются.
- Компенсации **идемпотентны**: повторный вызов не ломает состояние.
- При превышении таймаута шага (по умолчанию 10 сек) автоматически запускается компенсация.
Субд `futriix` является распределённой субд. Согласованность узлов в распределённом кластере определяется на основе протокола **Raft** с автоматическими выборами лидера. Поддерживаются одноузловой (для запуска на одном узле, без организации кластера) и многокластерный режимы, репликация данных (синхронная/асинхронная), мастер-мастер репликация и health-мониторинг узлов. <br>
Протокол Raft в субд был реализован для отказоустойчивости. Безопасность каналов и аутентификация узлов возложены на инфраструктуру ЗПС (изоляция сети, статическая маршрутизация, контроль администратора). Модель угроз ЗПС не предполагает наличие атакующего внутри кластерной сети.<br>
Шифрование Raft-трафика не реализовано, так как при развёртывании в ЗПС все межсерверные соединения находятся в пределах одного физически изолированного сегмента. В случае требования шифрования на уровне приложения, администратор ЗПС может использовать туннелирование (IPsec, WireGuard) средствами нижележащей сетевой инфраструктуры.
Автомасштабирование реализовано на основе комбинированного алгоритма **PHA (Predictive Horizontal Autoscaler)- Горизонтальный автомасштабировщик с прогнозированием нагрузки**
Это уровень, который считается "пределом нормы". Например: 80 % для CPU, 90 % для RAM, лимит RPS, при котором начинаются деградации. Отношение metric_value / metric_threshold даёт безразмерный коэффициент загрузки: 1.0 — на пороге, больше 1.0 — перегруз, меньше 1.0 — запас.
Позволяет учитывать, что разные ресурсы имеют разную критичность. Например, RAM можно сделать важнее, чем CPU, если приложение чувствительно к памяти. Веса могут быть любыми положительными числами; их не обязательно нормировать заранее — формула сама нормализует через знаменатель.
Для каждой метрики считаем "насколько мы превысили порог" (или насколько близки к нему), умножаем на важность этой метрики, затем складываем. Это даёт суммарную "оценку напряжённости" узла с учётом приоритетов.
Для защищиты субд futriix от перегрузки при всплесках входящей нагрузки, в ней реализован механизм **Backpressure (клапан обратного давления)**, реализующий алгоритм **"Buffer Ring (кольцевой буфер обратного давления)."**
Он реализует адаптивное откладывание запросов вместо их немедленного отклонения: когда система близка к насыщению, запросы не отбрасываются, а ненадолго помещаются в кольцевой буфер, чтобы дать ядру время обработать уже принятые операции.
Такой подход отличается от классического «reject при перегрузке» тем, что сглаживает пики, а не режет их, и сохраняет больше полезной работы при кратковременных всплесках.
Каждый слот хранит «билет» запроса: метаданные (тип, deadline, приоритет) и функцию продолжения resume(), которая будет вызвана, когда наступит очередь.
На каждом цикле проверки (например, раз в check_interval_ms) менеджер снимает метрики: загрузку CPU, памяти, длину очереди, число соединений. По порогам из конфигурации определяется уровень:
| Уровень | Условие | Действие |
|---------|---------|----------|
| `Low` | CPU < `cpu_threshold` и очередь < `queue_size_threshold` | запрос проходит сразу |
| `Medium` | один из порогов превышен | запрос помещается в кольцо на короткую задержку `low_delay_ms` |
| `High` | CPU > `cpu_threshold` и очередь > `queue_size_threshold` | запрос помещается в кольцо; при переполнении применяется `high_reject_prob` |
| `Critical` | система не успевает дренировать кольцо | запросы отклоняются с `503 Service Unavailable` |
Почему отдельная горутина: если бы запросы «дренировались» из того же потока, что их принимает, кольцо не сглаживало бы нагрузку, а просто перемещало её в вызывающий код. Дренажёр работает асинхронно и может приостанавливаться, если systemHasCapacity() возвращает `false`.
Дренажёр перед `resume()` проверяет: если `now > req.deadline` — запрос отклоняется с `504 Gateway Timeout`, а не выполняется «просроченным». Это гарантирует, что клиент получит ответ в предсказуемое время, даже если система перегружена.
* Не является очередью. Порядок FIFO не гарантируется при вытеснении по приоритету.
* Требует настройки под нагрузку. При слишком маленьком кольце и жёстких порогах возможны ложные срабатывания.
* Не заменяет rate limiting. Buffer Ring сглаживает всплески, но не ограничивает устойчивую скорость запросов — для этого нужен отдельный слой rate limiter перед API.
Кросс-датацентровая миграция данных позволяет переносить данные между географически распределенными кластерами futriix без остановки работы системы. Миграция основана на асинхронной репликации с использованием CDC (Change Data Capture) и устойчивой очереди изменений.
Миграция данных между датацентрами реализована на основе асинхронной репликации с **CDC (Change Data Capture)** и включает следующие ключевые компоненты:
1. Change Queue — устойчивая очередь изменений (до 100 000 записей), сохраняемая на диск. Каждое изменение получает уникальный LSN (Log Sequence Number) для отслеживания прогресса.
2. Checkpoint System — система чекпоинтов, позволяющая возобновить миграцию с места остановки. Чекпоинты сохраняются каждые 30 секунд и содержат информацию о последнем LSN и обработанных документах.
3. Delta Sync — после основной миграции система продолжает синхронизировать изменения, произошедшие во время миграции, обеспечивая консистентность данных.
4. Валидация — после завершения миграции выполняется выборочная проверка данных (по умолчанию 10% документов) с использованием SHA-256 контрольных сумм.
| **IDLE** | Начальное состояние, миграция не запущена | `migration start` | Запуск новой миграции |
| **PREPARING** | Сбор метаданных, анализ структуры данных, подсчёт документов | Автоматически после завершения подготовки | Мониторинг прогресса |
| **MIGRATING** | Основная передача данных из источника в приёмник | Автоматически после завершения передачи | `migration pause`, `migration status` |
| **DELTA_SYNC** | Синхронизация изменений, произошедших во время миграции | Автоматически после синхронизации | `migration pause`, `migration status` |
| **VALIDATING** | Проверка целостности данных (контрольные суммы) | Автоматически после валидации | `migration status` |
Для создания бекапов, в субд существуют команды `export` и `import`, позволяющие выгружать/загружать целые базы данных в формате **MessagePack**. Экспорт сохраняет документы с метаданными (версии, временные метки), импорт поддерживает пропуск существующих документов и детальную статистику.
СУБД Futriix предусмотрен удобный сетевой интерфейс для интеграции с веб‑приложениями — это RESTful API, который покрывает все основные операции над данными и служебными объектами системы.
API спроектирован с учётом требований современной веб‑разработки:
* Поддержка CORS позволяет выполнять запросы к СУБД из браузерных приложений, размещённых на других доменах, без проблем с политикой безопасности браузеров. <br>
* Аутентификация по X‑Session‑ID даёт простой и надёжный механизм управления сессиями: клиент получает идентификатор сессии после авторизации, а затем передаёт его в заголовке X-Session-ID для подтверждения прав на выполнение операций. Такой подход хорошо ложится на привычные схемы работы с сессионными токенами и легко встраивается в существующие стеки.<br>
* **CRUD‑операции над коллекциями** `(/api/db/{db}/{collection})` — полный набор действий для работы с данными: создание, чтение, обновление и удаление документов. Шаблоны URL позволяют адресовать конкретную базу данных и коллекцию, что удобно при мультитенантной архитектуре или при работе с несколькими логическими пространствами данных.
* **Управление индексами** `(/api/index/)` — инструменты для создания, изменения и удаления индексов, чтобы гибко настраивать производительность выборки под разные типы запросов.
* **Контроль доступа (ACL)** `(/api/acl/)` — настройка правил доступа к объектам СУБД: можно разграничивать права на уровне баз, коллекций, отдельных операций или даже по условиям над данными.
* **Работа с ограничениями** `(/api/constraint/)` — управление декларативными ограничениями целостности (например, enum‑списками, диапазонами, уникальностью и т. п.), которые помогают поддерживать корректность данных на уровне СУБД.
* **Администрирование кластера** `(/api/cluster/)` — операции по управлению топологией кластера: добавление и удаление узлов, перераспределение шардов, мониторинг состояния реплик и консенсуса (в том числе на базе Raft). Это особенно важно при динамическом масштабировании и обслуживании распределённой системы.
СУБД `futriiX` изначально проектировалась как распределённая система, которой удобно управлять из командной строки и через REST API. Однако для повседневной эксплуатации, наблюдения за состоянием кластера и быстрой реакции на инциденты удобнее иметь **веб-интерфейс**. Встроенный WebUI в ядро не входит — вместо этого `futriiX` интегрируется со стандартными инструментами мониторинга **Prometheus** и **Grafana**, которые вместе дают пользователю полноценный веб-интерфейс для наблюдения и управления данными: дашборды, графики, таблицы, алерты и произвольные выборки из REST API прямо в браузере.
Такая интеграция даёт три ключевых преимущества:
- **Единая точка наблюдения.** Все метрики кластера, хранилища, HTTP-трафика, репликации и SAGA-транзакций собираются в одном месте — в Grafana.
- **Промышленный стандарт.** Prometheus и Grafana — де-факто стандарт observability; их используют практически во всех production-окружениях, поэтому интеграция не требует экзотических зависимостей.
- **Кроссплатформенность.** Экспортёр метрик реализован на чистой стандартной библиотеке Go и работает одинаково на Linux и OpenIndiana (illumos) — там, где `futriiX` и запускается.
Далее описано, как включить экспорт метрик, подключить Prometheus и Grafana, и какие именно метрики и endpoint'ы доступны.
`futriiX` умеет отдавать метрики в формате **Prometheus text exposition**. Это значит, что вы можете:
- Подключить **Prometheus** как time-series базу и настроить pull-скрейпинг `/metrics`.
- Подключить **Grafana** к Prometheus — и получить дашборды по состоянию кластера, нагрузке, репликации, HTTP-трафику.
- Дополнительно использовать **Grafana JSON API (Infinity) datasource** для запросов к REST API (`/api/cluster/status`, `/api/db/...`) и построения табличных панелей с «сырыми» данными.
Метрики работают **одинаково на Linux и OpenIndiana (illumos)**: реализация использует только стандартную библиотеку Go (`net/http`, `sync/atomic`, `math`), без внешних зависимостей и без платформо-специфичных syscall'ов.
### Включение
В`config.toml`:
```toml
[metrics]
# Включить экспорт метрик в формате Prometheus
enabled=true
# Интервал сбора метрик в секундах (по умолчанию 15)
collect_interval_sec=15
```
Если секция отсутствует — метрики отключены (`enabled = false`) и используются дефолты. Если `enabled = true`, но `collect_interval_sec <= 0` — валидатор вернёт ошибку на старте.
### HTTP endpoints
После запуска `futriiX` доступны:
| Endpoint | Назначение |
|---|---|
| `GET /metrics` | Prometheus text exposition (`text/plain; version=0.0.4`). Endpoint **без аутентификации** — так принято в Prometheus-экосистеме, ограничивайте доступ на уровне сети/файрвола. |
| `GET /-/healthy` | Liveness-проба. Всегда `200 OK`, если процесс жив. |
| `GET /api/metrics` | JSON-снимок метрик (rate-limiter, store, cluster). Удобно для Grafana JSON API / Infinity datasource. |
**Grafana** — это платформа визуализации и наблюдаемости, которая превращает собранные Prometheus метрики в живые дашборды, графики и таблицы. Именно Grafana даёт конечному пользователю `futriiX`**веб-интерфейс**: не нужно ничего программировать и разворачивать собственный UI — достаточно подключить Grafana к Prometheus, и все метрики кластера, хранилища и HTTP-трафика становятся доступны в браузере. Дополнительно, через плагин **Infinity** (или встроенный JSON API datasource), Grafana умеет обращаться напрямую к REST API `futriiX` — это открывает доступ к «сырым» данным (список БД, статус кластера, документы) в виде таблиц и панелей.
- Метрики не содержат пользовательских данных — только агрегаты и labels с именами БД/узлов/HTTP-путей.
### Отключение
В`config.toml`:
```toml
[metrics]
enabled=false
```
При этом:
- HTTP-endpoint `/metrics` по-прежнему вернёт базовые process-метрики (`futriis_up`, `futriis_uptime_seconds`).
- Периодический сбор и публикация в реестр останавливаются.
### Диагностика
| Симптом | Причина | Решение |
|---|---|---|
| `/metrics` возвращает 404 | HTTP-сервер не запустился или не зарегистрировал маршрут | Проверить логи, проверить `cfg.API.Port`; `/metrics` регистрируется всегда. |
| Метрики есть, но только `futriis_up` / `futriis_uptime_seconds` | Коллектор не установлен (`SetMetricsCollector` не вызывался) или `metrics.enabled = false` | Включить `[metrics].enabled = true`; проверить, что `main.go` передаёт коллектор в HTTP-сервер. |
| Метрики не обновляются | Интервал слишком большой, либо коллектор остановлен | Проверить `collect_interval_sec`; посмотреть в логах `Prometheus metrics collector started`. |
| Grafana не видит Prometheus | Неверный URL / network policy | `curl http://prometheus-host:9090/-/healthy`; проверить firewall между Grafana и Prometheus. |
Для расширения функциональных возможностей субд **без изменения её исходного кода**, в futriix была реализована система расширения функциональности через Lua-скрипты с изолированным окружением.<br>
**Плагины как инструмент написания движков для futriix**
Для написания нового движка (LSM-дерева, key-value или time-series) необходимо два файла: файл с названием самого движка с расширением **.lua**
и файл **Манифест-плагина**с расширением **.json**
**Манифест плагина-движка** — это JSON-файл, который сопровождает Lua-скрипт плагина и предоставляет системе метаданные о плагине. Манифест необходим для корректной загрузки, регистрации и управления плагинами, реализующими кастомные движки хранения данных.
Расположение и именование
Манифест должен располагаться в той же директории, что и Lua-скрипт плагина (по умолчанию `/futriix/plugins`), и иметь идентичное имя файла с расширением **.json**. Например:
| `api_version` | string | ✅ | Версия API СУБД, с которой совместим плагин |
| `engine_type` | string | ✅ | **Ключевое поле**. Определяет, что плагин является движком хранения. Значение используется как идентификатор движка при создании коллекций |
| `min_go_version` | string | ❌ | Минимальная версия Go, необходимая для работы плагина |
| `dependencies` | array | ❌ | Список зависимостей от других плагинов |
| `entry_point` | string | ❌ | Имя Lua-функции-фабрики, создающей экземпляр движка. По умолчанию: `create_engine` |
| `created_at` | int64 | ❌ | Время создания манифеста (Unix timestamp в миллисекундах) |
| `updated_at` | int64 | ❌ | Время последнего обновления манифеста |
**Структура зависимости**
Каждая зависимость в массиве `dependencies` имеет следующую структуру:
| Поле | Тип | Обязательное | Описание |
|------|-----|--------------|----------|
| `name` | string | ✅ | Имя зависимого плагина |
| `version` | string | ❌ | Точная версия зависимого плагина (если указана, требует точного соответствия) |
* Увеличивайте MAJOR-версию при несовместимых изменениях API движка
* Увеличивайте MINOR-версию при добавлении новой функциональности
* Увеличивайте PATCH-версию при исправлении ошибок
**Обработка ошибок**
При отсутствии манифеста система пытается загрузить плагин в "упрощённом режиме", используя значения по умолчанию. Однако для плагинов-движков манифест является обязательным, так как поле engine_type необходимо для корректной регистрации.
Ошибки при разборе манифеста логируются, но не препятствуют загрузке Lua-скрипта (если это не плагин-движок). При критических ошибках (отсутствие engine_type у движка) загрузка прерывается с соответствующим сообщением.
В futriix реализована многоуровневая система контроля доступа, основанная на **ACL (Access Contol Lists -Списки контроля доступа**) с аутентификацией по сессиям. В ней поддерживаются следующие роли (read, write, delete, admin) с гранулярным контролем на уровне базы данных и коллекции.
```sh
# Вход в систему
futriix:~> acl login admin admin
✓ Logged in as 'admin' with role 'admin'
# Выход из системы
futriix:~> acl logout
✓ Logged out
# Назначение прав доступа (после входа как admin)
futriix:~> acl login admin admin
✓ Logged in as 'admin' with role 'admin'
futriix:~> use company
✓ Switched to database 'company'
# Назначение прав на чтение
futriix:~> acl grant employees reader r
✓ Permissions 'r' granted to role 'reader' on collection 'employees'
# Назначение прав на чтение и запись
futriix:~> acl grant employees editor rw
✓ Permissions 'rw' granted to role 'editor' on collection 'employees'
# Назначение полных прав (администратор коллекции)
futriix:~> acl grant employees admin rwda
✓ Permissions 'rwda' granted to role 'admin' on collection 'employees'
**Триггер**— это действие в базе данных, автоматически запускаемое при добавлении, изменении или удалении записи. Чаще всего триггеры нужны для математических вычислений, а также проведения аудита (для автоматической записи в лог или базу данных действий, которые необходимо отслеживать в рамках проведения аудита.) <br>
Сжатие данных в СУБД futriix, использует алгоритм компрессии **Brotli**, предназначенного для уменьшения объёма хранимых документов в оперативной памяти и на жёстком диске, что позволяет эффективнее использовать доступные ресурсы при работе с большими объёмами информации.
Алгоритм Brotli, разработанный компанией Google, обеспечивает сжатие с коэффициентом, на 20–26% лучшим по сравнению с классическим Gzip при сопоставимой скорости распаковки, что делает его оптимальным выбором для систем с интенсивными операциями чтения.
Основные преимущества Brotli включают: использование предопределённого словаря часто встречающихся последовательностей байт, адаптивное кодирование с переменной длиной кода, поддержку 11 уровней сжатия (от быстрого до максимально плотного) и высокую скорость распаковки, критически важную для быстрого доступа к документам. В futriix сжатие применяется автоматически при превышении порогового размера документа (настраивается через compression.MinSize), при этом каждый документ хранит флаг Compressed и оригинальный размер для последующего контроля эффективности.
В данном разделе- **ЧАВО (Часто задаваемые Вопросы и Ответы)** собраны ответы на самые частые вопросы — чтобы вы быстро разобрались в работе проекта и не тратили время на поиск очевидных вещей. Если не нашли нужного ответа — напишите в `issues`: обратная связь помогает нам расставлять приоритеты.<br> Дальше — раздел «План развития»: там показаны, какие улучшения уже реализованы, а каких ждать в будущем.
**Ответ: «2» — номер версии: здесь собраны ключевые компоненты (шардинг, WAL, Batch и др.).**
**i2i2 — математическая метафора: хотя ii — мнимая единица, её квадрат даёт абсолютно точный результат (i2=−1i2=−1). Так и Futriix: даже в сложной распределённой среде с параллельными операциями (wait‑free, lock‑free) система выдаёт строго предсказуемые результаты — за счёт Raft, Batch и WAL. Это близко философии OpenIndiana/Illumos: детерминизм и контроль над ресурсами.**
- [x] Реализовать мульти-мастер асинхронную репликацию через файл конфигурации
- [x] Реализовать логирование для субд
- [x] Реализовать поддержку синхронной мастер-мастер репликации
- [x] Реализовать базовую поддержку протокола Raft
- [x] Реализовать поддержку индексов (первичные индексы, вторичные индексы)
- [x] Реализовать поддержку протокола MessagePack
- [x] Написать базовые тесты (интеграционный, функциональный, регрессионный, нагрузочный, smoke-тест для ядра субд "futriix")
- [x] Добавить механизм плагинов на языке lua, загружаемых в субд при её запуске, расширяющих её базовый функционал, не изменяя исходный код субд
- [x] Реализовать поддержку HTTP-restfull API
- [x] Реализовать сжатия данных в субд на основании протокола "Brotli"
- [x] Реализовать импорт и экспорт дампа субд в формате "MessagePack"
- [x] Исправить ошибки записи журнала логов (в журнал лога кроме текущего времени добавить текущий год)
- [x] Скрипты сборки "build.sh" и "vendor_build.sh" переписаны таким образом, чтобы проект не зависел от компилятора "gcc", т.е. напиши реализацию так чтобы его не нужно было устанавливать отдельно в операционной системе "OpenIndiana Hipster"
- [x] Библиотека "raft-boltdb" заменить на встроенное файловое хранилище
- [x] Реализовать уникальные и составные индексы
- [x] Реализовать временные метки для основных объектов субд (таппл, коллекция, документ, поле, индекс, транзакция, ACL, узел кластера)
- [x] Реализовать атомарнуя запись бэкапов (Обеспечение целостности файлов бэкапов)
- [x] Реализована оптимизация ядра субд (удалён файл "/internal/storage/storage.go", методы "Storage" и "NewStorage" вынесены в "/internal/storage/engine.go")
- [x] Реализация записи "пакетами записи" для WAL-журнала (flushBatch)
- [x] Реализовать Gossip Protocol (Протокол сплетен) (механизм автоматического обнаружения узлов в кластере, обмен информацией между узлами нагрузка,health про протоколу UDP, поддержка seed-узлов для начального обнаружения, автоматическое обновление списка членов кластера)
- [x] Реализовать Self-Healings (Механизмы самоисцеления) (Автоматический мониторинг состояния всех узлов кластера,Обнаружение сбоев с пороговым значением (Failure Threshold, автоматическое восстановление: перезапуск, переподключение, перебалансировка, отслеживание истории восстановлений и сбор метрик)
- [x] Реализовать Dynamic Configuration (Динамическая конфигурация) (централизованное хранение конфигурации в Raft-логе, изменение параметров на лету без перезапуска узлов, версионирование и история изменений, подписка на изменения для компонентов системы)
- [ ] Реализовать геораспределённую миграцию (Региональные зоны Поддержка нескольких availability zones с приоритетом выбора,Чтение из ближайшей реплики Маршрутизация запросов к географически ближайшему узлу,Асинхронная межрегиональная репликация Снижение задержек для глобальных кластеров)
- [ ] Реализовать Read-only лидер (Оптимизация запросов на чтение через локальные индексы)
- [ ] Реализовать Snapshot streaming (Передача снапшотов через отдельный канал без блокировки)
- [ ] Интеграцию с мониторинговыми системами (Prometheus, Grafana)
- [ ] Реализовать полноценную систему бекапирования с возможностью определения корректности созданного бекапа и кроссдацентровых решений по автоматическому копироваю бекапа в другой дацентр
- [ ] Реализовать коннекторы к современным языкам программирования (C, C++, Java, Python, Go)
- [ ] Реализовать утилиту тестирования сервера на количество запросов на чтение/запись
См. [Открытые проблемы](https://source.futriix.ru/gvsafronov/futriixw/issues) полный список предлагаемых функций (и известных проблем).
По вопросам эксплуатации, производительности и консультации по настройки конфигурации, просьба обращаться по контактам указанными ниже в данном разделе.<br>
**Обращаем ваше внимание, что личная почта — это технический контакт, предназначенный только для:**
* **Сообщений о критических уязвимостях (с подробным PoC)**
* **Предложений о сотрудничестве**
* **Преложений по улучшений futriix**
Обращаем ваше внимание, что письма без четко сформулированной темы, вопроса или предложения рассматриваться не будут.