From 6b9ee6b3d2b7d2633d3917c7a8880cd7c90085dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=93=D1=80=D0=B8=D0=B3=D0=BE=D1=80=D0=B8=D0=B9=20=D0=A1?= =?UTF-8?q?=D0=B0=D1=84=D1=80=D0=BE=D0=BD=D0=BE=D0=B2?= Date: Sat, 3 Oct 2026 21:24:07 +0000 Subject: [PATCH] Update README.md --- README.md | 199 ++++++++++++++++++++++-------------------------------- 1 file changed, 79 insertions(+), 120 deletions(-) diff --git a/README.md b/README.md index c1c496c..14554eb 100644 --- a/README.md +++ b/README.md @@ -618,7 +618,7 @@ $ ./futriix В субд **"futriix"** используется два журнала для ведение логов: `"futriix.log"`-основной журнал, в котором ведутся логи при работе в субд через терминал. -**futriix.log** — основной системный журнал, фиксирующий все события жизненного цикла СУБД: запуск/остановку сервера, инициализацию компонентов (транзакции, Raft-координатор, ACL), состояние кластера и критические ошибки выполнения запросов. +**futriix.log** — основной системный журнал, фиксирующий все события жизненного цикла СУБД: запуск/остановку сервера, инициализацию компонентов (batch, Raft-координатор, ACL), состояние кластера и критические ошибки выполнения запросов. Журнал использует структурированный JSON-формат (для webui.log) и текстовый формат с временными метками (для futriis.log), что обеспечивает удобный парсинг и интеграцию с системами мониторинга. @@ -942,148 +942,109 @@ futriix:~> db.startSession()

(К началу)

-## Транзакции +## Batch +# Механизм надёжности и восстановления в СУБД futriix -В СУБД **futriix** для обеспечения надёжности (durability) и быстрого восстановления БД из резервной копии реализована полноценная поддержка WAL (Write-Ahead Logging). Журнал WAL по умолчанию хранится в файле futriix.wal, находящемся в каталоге futriix. +В СУБД **futriix** для обеспечения надёжности (durability), атомарности и быстрого восстановления базы данных реализована двухуровневая система журналирования: -СУБД поддерживает ACID‑транзакции с MVCC (Multi‑Version Concurrency Control) — для локальной атомарности и изоляции на уровне отдельных узлов кластера. Для распределённых операций используется паттерн SAGA с оркестратором: глобальная согласованность достигается через последовательность компенсируемых локальных транзакций, управляемых централизованным оркестратором, который отслеживает состояние шагов, инициирует компенсацию при сбоях и гарантирует завершение сценария в согласованном состоянии. +1. **WAL (Write-Ahead Log)** — сегментированный журнал предзаписи для **batch-операций** (атомарных групп изменений). По умолчанию хранится в каталоге `futriix/wal_segments/`. +2. **AOF (Append-Only File)** — журнал дозаписи для **одиночных мутаций**, выполненных вне batch (прямые вызовы `Insert`, `Update`, `Delete`, `Restore`, а также операции из REPL, HTTP-API и Lua-плагинов). По умолчанию хранится в каталоге `futriix/aof/`. -Парадигма eventual consistency обеспечивает согласованность данных в распределённой среде: изменения распространяются асинхронно между узлами, а финальное согласованное состояние достигается со временем с учётом гарантий доставки событий и правил разрешения конфликтов. Такой подход позволяет сохранить высокую доступность и производительность даже при временных сетевых сбоях. +Такое разделение даёт: +- **Атомарность** для сложных составных операций (batch). +- **Гарантированную сохранность** каждой отдельной мутации (AOF). +- **Быстрое восстановление** через воспроизведение обоих журналов при старте. +- **Разделение нагрузки**: batch-операции пишутся в WAL сегментами по 64 МБ, одиночные мутации — в AOF с ротацией по 64 МБ. -Доступны команды, с восстановлением после сбоев через журнал предзаписи: +--- - * `startSession()`- Начать сессию (устойчивый контекст взаимодействия клиента с СУБД, в рамках которого поддерживается состояние) в субд в рамках которой будет открыта транзакция - * `startTransaction()`- Начать транзакцию - * `commitTransaction()`- Сделать коммит транзакцию - * `abortTransaction()` - Прервать транзакцию +## Что такое Batch -> [!IMPORTANT] -> **Матрица гарантий согласованности**
-> Ниже приведена матрица гарантий согласованности, призванная дать ответ на потенциальный возможный вопрос пользователя: "А вдруг у меня -> данные потеряются"? +**Batch** — это группа операций, применяемых **атомарно**: либо все операции из группы применяются, либо ни одна. Batch заменяет полноценные ACID-транзакции в локальном узле и работает по принципу «всё или ничего» через WAL. -# Матрица гарантий согласованности Futriix +**Ключевые свойства batch:** -| Операция | Уровень изоляции | Поведение при нормальной работе | Поведение при сетевых сбоях | Восстановление после сбоя | -|----------|------------------|--------------------------------|----------------------------|---------------------------| -| **Чтение (Read)** | **Read Committed** + MVCC | • Чтение всегда возвращает только закоммиченные данные
• MVCC предоставляет снапшот на момент начала чтения
• Используется Visibility Map для быстрого доступа к версиям
• Кеширование через ReadTimestampCache | • При потере соединения - операция повторяется автоматически (идиемпотентность)
• Если узел недоступен - запрос перенаправляется к реплике (Raft)
• Чтение из кэша возможно при недоступности основного узла | • После восстановления узла - чтение продолжается с момента прерывания
• WAL не требуется для чтения (только для записи)
• Снапшоты MVCC восстанавливаются из documentVersions | -| **Запись (Write)** | **Read Committed** | • Запись сначала сохраняется в WAL (атомарно)
• Затем применяется к in-memory структурам
• Индексы обновляются атомарно с документом
• Атомарное обновление метаданных коллекции | • Если WAL запись не подтверждена - операция не применяется
• При сбое до коммита - данные не теряются (WAL)
• При потере лидера (Raft) - запись перенаправляется к новому лидеру
• Используется fsync для гарантии записи на диск | • После восстановления - запись повторяется из WAL
• Автоматическое применение WAL при загрузке
• Консистентность через LSN (Log Sequence Number)
• Segmented WAL позволяет восстанавливать частичные записи | -| **Транзакция (BEGIN...COMMIT)** | **Read Committed / Repeatable Read** (MVCC) | • Транзакция атомарна: все или ничего
• MVCC предоставляет снапшот на момент начала транзакции
• Операции внутри транзакции изолированы
• Savepoints для частичного отката
• Deadlock detection с автоматическим abort‑ом | • При сбое в середине транзакции — автоматический откат
• WAL гарантирует восстановление закоммиченных транзакций
• SAGA с оркестратором для распределённых транзакций с таймаутом (10 сек)
• Pending‑шаги Saga автоматически компенсируются при таймауте | • Асинхронное восстановление из WAL
• Восстановление только закоммиченных транзакций
• Pending‑шаги SAGA проверяются на таймаут
• Recovery Manager обрабатывает записи параллельно | -| **Индексация** | **Read Committed** | • Индексы обновляются атомарно с документом
• Уникальные индексы проверяются перед вставкой
• Индексы хранятся в sync.Map (wait-free)
• Поддержка составных индексов | • Индексы восстанавливаются из данных при загрузке
• При сбое - индексы перестраиваются автоматически
• Консистентность через LSN
• Уникальные индексы проверяются при восстановлении | • Индексы перестраиваются из документов при старте
• WAL содержит операции обновления индексов
• Автоматическое восстановление целостности индексов
• Проверка дубликатов при восстановлении уникальных индексов | -| **Удаление (Delete)** | **Read Committed** | • Soft delete сохраняет данные (метка deleted_at)
• Удаление из индексов происходит атомарно
• Физическое удаление - только после подтверждения
• Атомарное обновление счётчиков | • При сбое - операция повторяется из WAL
• Soft delete защищает от потери данных
• Окончательное удаление - после подтверждения всеми репликами
• Permanent delete требует подтверждения | • Soft delete записи восстанавливаются из WAL
• Permanent delete повторяется из WAL
• Счётчики документов восстанавливаются атомарно | -| **Репликация (Raft)** | **Linearizable** (для записей) / **Read Committed** (для чтений) | • Записи проходят через Raft-журнал
• Линейная консистентность для записей
• Чтения могут быть из реплик (Read Committed)
• Автоматическое переизбрание лидера | • При сбое лидера - автоматический выбор нового (Raft)
• Запросы перенаправляются к новому лидеру
• Данные согласованы через журнал Raft
• Read-запросы могут обслуживаться репликами | • Raft журнал восстанавливается из WAL
• Новый лидер применяет все закоммиченные записи
• Реплики синхронизируются с лидером
• Автоматическое восстановление кластера | -| **Шардирование (Range Shards)** | **Read Committed** | • Диапазонные шарды с динамическим сплитом/мерджем
• Данные распределены по диапазонам ключей
• Предсказуемая нагрузка на узлы
• Возможность предварительного добавления узлов под горячие диапазоны | • При сбое узла - шард перераспределяется
• Данные реплицируются для отказоустойчивости
• Автоматический сплит при переполнении шарда
• Мердж при уменьшении нагрузки | • Шарды восстанавливаются из чекпоинтов
• WAL применяется к каждому шарду
• Балансировка после восстановления
• Автоматическое перераспределение | -| **Checkpoint / Snapshot** | **Read Committed** | • Периодическое сохранение снапшотов (каждые 5 мин)
• Атомарная запись с временным файлом
• Контрольная сумма для верификации
• Сжатие снапшотов (gzip)
• Хранение последних N чекпоинтов | • При сбое во время создания - временный файл удаляется
• Предыдущий чекпоинт остаётся целым
• Атомарное переименование гарантирует целостность
• WAL LSN сохраняется в чекпоинте | • Загрузка из последнего валидного чекпоинта
• Применение WAL после чекпоинта
• Проверка контрольной суммы при загрузке
• Автоматическое восстановление из чекпоинта | -| **WAL (Write-Ahead Log)** | **Persistent** | • Все записи сначала идут в WAL
• Segmented WAL с ротацией (64 MB)
• Пакетная запись с fsync
• CRC32 для верификации целостности
• Асинхронная запись с буферизацией | • При сбое — WAL сохраняет все записи
• fsync гарантирует запись на диск
• Segments позволяют восстанавливать частичные данные
• Индекс LSN для быстрого поиска | • Полное восстановление из WAL
• Асинхронный Recovery Manager
• Параллельное применение записей (4 воркера)
• Восстановление Saga с оркестратором (pending‑шагов и компенсаций) | -| **SAGA с оркестратором** | **Read Committed** | • Оркестрированная Saga для распределённых транзакций
• Последовательность шагов с компенсационными действиями для каждого этапа
• Оркестратор управляет порядком выполнения и обработкой отказов
• Таймаут на выполнение шага (10 сек) | • При сбое оркестратора — шаг остаётся в незавершённом состоянии
• Автоматическая компенсация при превышении таймаута
• Отдельные шаги могут выполняться автономно на узлах
• Pending шаги и компенсации сохраняются в WAL | • Восстановление pending Saga‑шагов при старте
• Проверка таймаутов и статуса шагов
• Автоматический запуск компенсационных действий для просроченных шагов
• Координация узлов для завершения/отката цепочки шагов | -| **Deadlock Detection** | **N/A** | • Обнаружение циклических ожиданий
• Автоматический abort одной из транзакций
• Периодическая проверка (каждую секунду)
• Поддержка распределённых deadlock-ов | • При сетевых задержках - возможны ложные срабатывания
• Abort транзакции с последующим повтором
• Распределённый deadlock detection через координатор | • Deadlock граф восстанавливается из активных транзакций
• Автоматическое разрешение при старте
• Логирование deadlock-ов для анализа | -| **MVCC (Multi-Version Concurrency Control)** | **Repeatable Read** (внутри транзакции) | • Каждая запись хранит несколько версий
• Чтение получает версию на момент начала транзакции
• Автоматическая очистка старых версий (каждые 5 мин)
• Хранение до 100 версий на документ
• Retention: 7 дней | • Версии сохраняются в памяти и WAL
• При сбое - версии восстанавливаются из WAL
• Visibility Map ускоряет проверку видимости
• ReadTimestampCache для быстрого доступа | • Версии восстанавливаются из WAL записей
• Автоматическая очистка устаревших версий
• Восстановление Visibility Map
• Кеш перестраивается при загрузке | +- **Атомарность** через WAL: сначала весь batch сериализуется и записывается в WAL с `fsync`, только после успешной записи операции применяются к in-memory структурам. +- **Откат при ошибке применения**: если операция падает на середине применения, уже применённые операции откатываются (best-effort) — полная атомарность гарантируется на уровне WAL при восстановлении. +- **Короткое время жизни**: batch создаётся, наполняется операциями и коммитится в рамках одной логической операции. Не поддерживает savepoints, таймауты, распределённую координацию. +- **Реестр активных batch'ей**: `BatchManager.activeBatches` (см. `runtime_limits.go`) защищает документы, участвующие в незакоммиченном batch, от вытеснения (eviction) при нехватке памяти. +- **AOF-дублирование**: после коммита batch также пишется в AOF для ускорения восстановления. -### Условные обозначения: +**Операции batch:** -| Символ | Значение | -|--------|----------| -| ✅ **Гарантировано** | Операция гарантирует консистентность при любых условиях | -| ⚠️ **Частично** | Требует дополнительных проверок или имеет ограничения | -| 🔄 **Автоматически** | Восстановление происходит без вмешательства пользователя | -| 📊 **Настраивается** | Поведение можно настроить через конфигурацию | +| Команда | Действие | +|---------|----------| +| `NewBatch(db, coll)` | Создать новый batch для указанной БД и коллекции | +| `batch.AddInsert(doc)` | Добавить операцию вставки документа | +| `batch.AddUpdate(docID, updates)` | Добавить операцию обновления | +| `batch.AddDelete(docID)` | Добавить операцию удаления | +| `batch.AddRestore(docID)` | Добавить операцию восстановления | +| `batch.Commit()` | Применить batch атомарно через WAL | -## Ключевые гарантии: +--- -1. **ACID**: Все операции соответствуют ACID благодаря WAL + MVCC + SAGA c оркестратором -2. **Durability**: fsync + WAL гарантируют сохранность данных -3. **Consistency**: Чекпоинты + контрольные суммы + верификация -4. **Isolation**: MVCC + Read Committed + Repeatable Read внутри транзакций -5. **Availability**: Raft + репликация + автоматическое переизбрание лидера -6. **Partition Tolerance**: SAGA c оркестратором + таймауты + автоматический откат +### Что такое AOF +**AOF (Append-Only File)** — журнал дозаписи, который логирует **каждую отдельную мутацию**, выполненную вне batch. Это нужно, потому что прямые вызовы `coll.Insert()`, `coll.Update()`, `coll.Delete()` идут мимо WAL, и без AOF такие изменения могли бы потеряться при сбое. +**Ключевые свойства AOF:** -> [!TIP] -> WAL- это журнал предзаписи транзакций, который в субд **futriix** выполняет следующие действия: -> 1. Хранит все операции транзакций до их фиксации (INSERT, UPDATE, DELETE) -> 2. Записывает каждое изменение последовательно с LSN (Log Sequence Number) -> 3. Используется для восстановления после сбоя через recoverFromWAL() -> 4. Формат: бинарный с CRC-контролем, размером записи и типом (Transaction/Checkpoint) -> 5. Расположение: /futriix/futriix.wal (один файл) +- **Формат**: JSON-lines (по одной JSON-записи на строку) с CRC32 для верификации целостности. +- **Ротация**: файлы разбиваются по размеру 64 МБ, имена вида `aof_.log`. +- **fsync**: каждая запись синхронизируется с диском через `file.Sync()` для гарантии сохранности. +- **Восстановление при старте**: `ReplayAOF(storage)` читает все файлы и применяет операции к хранилищу. +- **Идемпотентность**: повторное применение операции не ломает состояние (insert/update/delete идемпотентны по ключу). +- **Автоматическое логирование**: методы `Collection.Insert`, `Update`, `Delete`, `PermanentDelete`, `RestoreDeleted` вызывают `LogAOFInsert`, `LogAOFUpdate`, `LogAOFDelete`, `LogAOFRestore` соответственно. -> [!TIP] -> **Кроме того существуют так называемые **Периодические снимки состояния** журнала предзаписи, которые выполняют следующие функции:** -> 1. Фиксируют состояние всех активных транзакций на момент создания -> 2. Создаются автоматически каждые **5 минут (300 секунд)** -> 3. Именуются по маске: `futriis.wal.checkpoint.{timestamp}` -> 4. Хранят сжатое состояние: последний LSN + активные транзакции -> 5. Автоматически очищаются: остаётся только 5 последних чекпоинтов -> 6. Расположение: `/futriix/wal.checkpoint.wal` (несколько файлов файл) -> **Подводя итог, хочется отметить следующее: журнал предзаписи транзакций и периодические снимки состояния работают следующим образом:** -> 1. Штатная работа: WAL пишет каждую транзакцию -> 2. Периодически: создаётся checkpoint (снимок активных транзакций) -> 3. При сбое: восстанавливаемся с последнего checkpoint + доигрываем операции из WAL +**Типы записей AOF:** +| Тип | Описание | +|-----|----------| +| `insert` | Вставка документа | +| `update` | Обновление документа | +| `delete` | Удаление документа (soft или permanent) | +| `restore` | Восстановление мягко удалённого документа | -```sh -# Начало сессии (с временем создания сессии) -futriix:~> db.startSession() -✓ Session started: session_12345 at 2026-01-15 10:55:15.123 +--- -# Начало транзакции в рамках сессии -futriix:~> session.startTransaction() -✓ Transaction started: TX_67890 at 2026-01-15 10:55:18.456 +### SAGA для распределённых операций -# Выполнение операций в транзакции (с временем выполнения) -futriix:~> insert employees name=New User,position=Trainee,age=22 -✓ Document inserted with ID: 550e8400-e29b-41d4-a716-446655440005 (created at: 2026-01-15 10:55:21.789) +Для **распределённых** операций (между узлами кластера, между сервисами, для долгоживущих бизнес-процессов) используется паттерн **SAGA с оркестратором**: -futriix:~> update employees 550e8400-e29b-41d4-a716-446655440005 status=active -✓ Document '550e8400-e29b-41d4-a716-446655440005' updated at 2026-01-15 10:55:24.012 +- Глобальная согласованность достигается через последовательность **компенсируемых локальных шагов**. +- Каждый шаг SAGA может использовать **batch** для гарантии атомарности внутри себя. +- Оркестратор отслеживает состояние шагов, инициирует **компенсацию** при сбоях и гарантирует завершение сценария в согласованном состоянии. +- Состояние SAGA персистентно хранится в JSON-файлах (директория `saga_states/`), при старте pending-шаги восстанавливаются, а просроченные — компенсируются. +- Компенсации **идемпотентны**: повторный вызов не ломает состояние. +- При превышении таймаута шага (по умолчанию 10 сек) автоматически запускается компенсация. -# Подтверждение транзакции (с временем коммита) -futriix:~> session.commitTransaction() -✓ Transaction committed successfully at 2026-01-15 10:55:27.345 +**Пример SAGA с batch внутри шага:** -# Откат транзакции (при ошибке) (с временем отката) -futriix:~> session.startTransaction() -✓ Transaction started: TX_67891 at 2026-01-15 10:56:10.123 +```go +saga := sagaManager.BeginSaga("order_flow") -futriix:~> insert employees name=Test User,position=Test,age=25 -✓ Document inserted with ID: 550e8400-e29b-41d4-a716-446655440006 (created at: 2026-01-15 10:56:13.456) +saga.AddStep("create_order", + func() error { + batch := NewBatch("shop", "orders") + batch.AddInsert(orderDoc) + batch.AddUpdate("inv_1", map[string]interface{}{"qty": 5}) + return batch.Commit() // атомарность шага через WAL + }, + func() error { + batch := NewBatch("shop", "orders") + batch.AddDelete(orderDoc.ID) + batch.AddUpdate("inv_1", map[string]interface{}{"qty": 10}) + return batch.Commit() // атомарность компенсации + }, + nil) -futriix:~> session.abortTransaction() -✓ Transaction aborted, changes rolled back at 2026-01-15 10:56:16.789 +saga.AddStep("reserve_payment", + func() error { return paymentClient.Reserve(orderID, amount) }, // внешний вызов + func() error { return paymentClient.Cancel(orderID) }, + nil) -# Просмотр активных транзакций (с временем начала) -futriix:~> show transactions -=== Active Transactions === - ID: TX_67892, Status: active, Operations: 2, Started: 2026-01-15 10:57:00.123 - - INSERT: company.employees [user-uuid-001] - - UPDATE: company.employees [user-uuid-002] - ID: TX_67893, Status: active, Operations: 1, Started: 2026-01-15 10:57:05.456 - - DELETE: company.employees [user-uuid-003] - -# Просмотр сессий (с временем создания) -futriix:~> show sessions -=== Active Sessions === - session_12345 - Created: 2026-01-15 10:55:15.123, Last active: 2026-01-15 10:57:30.456 - session_12346 - Created: 2026-01-15 10:56:20.789, Last active: 2026-01-15 10:57:15.234 - - -# Статистика транзакций с временными метками - futriix:~> stats transactions -=== Transaction Statistics === - Total transactions: 150 - Committed: 145 (96.7%) - Aborted: 5 (3.3%) - - Average duration: 234 ms - Min duration: 45 ms - Max duration: 1523 ms - - Transactions by hour: - 10:00 - 11:00: 45 transactions - 11:00 - 12:00: 52 transactions - 12:00 - 13:00: 38 transactions -``` +sagaManager.Execute(saga)

(К началу)

@@ -2814,7 +2775,7 @@ futriix:~> doc compression employees 550e8400-e29b-41d4-a716-446655440000 - [x] Реализовать поддержку триггеров (обратных вызовов) - [x] Реализовать поддержку многопоточности - [x] Реализовать неблокирующие чтение/запись -- [x] Реализовать неблокирующие транзакции +- [x] Реализовать неблокирующие batch-команды (аналог batch в субд Valkey) - [x] Реализовать constraints (Ограничения) - [x] Реализовать мульти-мастер асинхронную репликацию через файл конфигурации - [x] Реализовать логирование для субд @@ -2832,7 +2793,6 @@ futriix:~> doc compression employees 550e8400-e29b-41d4-a716-446655440000 - [x] Библиотека "raft-boltdb" заменить на встроенное файловое хранилище - [x] Реализовать уникальные и составные индексы - [x] Реализовать временные метки для основных объектов субд (таппл, коллекция, документ, поле, индекс, транзакция, ACL, узел кластера) -- [x] Оптимизировать транзакции под высокие нагрузки (Реализовать: Пакетную запись WAL - вместо синхронной записи каждой операции, используется асинхронная запись пакетами по 100 записей, Буферизацию записей - 64KB буфер для WAL записей, Периодическую синхронизацию - синхронизация с диском каждые 5 секунд вместо каждой записи, Чекпоинты - периодическое создание контрольных точек состояния, Атомарные операции - использование atomic.Value и sync.Map для wait-free доступа) - [x] Реализовать MVCC версионирование - поддержка множественных версий документов - [x] Реализовать временные метки для объектов субд (Ограничений, Импорта-Экспорта, Триггеров, Lua-плагинов) - [x] Реализовать обработку состояний "split-brain" @@ -2852,12 +2812,11 @@ futriix:~> doc compression employees 550e8400-e29b-41d4-a716-446655440000 - [x] Реализовать Distributed Transactions - двухфазный коммит для распределённых транзакций - [x] Реализовать Deadlock Detection - циклический детектор дедлоков с таймаутами (DFS по графу ожидания) - [x] Реализовать Transaction Timeout - настраиваемый таймаут для долгих транзакций -- [x] Реализовать Savepoints - точки сохранения внутри транзакции для частичного отката - [x] Вынести настройи настройки MVCC,WAL и настройки плагинов из исходного кода проекта в файл конфигурации "config.toml" - [x] Реализовать выделение жирным шифтом все информационные сообщения в скриптах сборки - [x] Реализовать ограничения на количество создаваемых Lua-состояний в плагинах - [x] Реализовать WAL recovery сделать асинхронным для ускорения скорости работы субд -- [x] Реализовать SAGA c оркестратором (Распределённые транзакции) +- [x] Реализовать SAGA c оркестратором (Распределённые batch) - [x] Голосование узлов перед коммитом в протоколе Raft - [x] Реализовать автоматическое масштабирование - [x] Реализовать TLS, backpressure