FoundationDB — распределённое хранилище «ключ — значение» с полноценными ACID-транзакциями. Оно не пытается быть универсальной SQL-базой: вместо этого даёт строгий, предсказуемый фундамент, поверх которого строят слои — документные модели, очереди, каталоги, графы и специализированные API. Такой подход ценят за то, что транзакции, отказоустойчивость и масштабирование решаются на нижнем уровне, а прикладная логика не обрастает самодельными блокировками.
Типичные задачи для такой базы — метаданные кластера, конфигурации сервисов, учётные записи, очереди заданий и счётчики. Аналитику и отчёты поверх неё не строят: для сканирования таблиц и сложных соединений лучше подходит отдельное хранилище.
Модель данных и транзакции
Ключи и значения — произвольные байтовые строки. Ключи упорядочены лексикографически, поэтому диапазонный поиск работает как в B-дереве. Декоратор транзакции повторяет её при конфликте, но только если код оформлен как идемпотентная функция. Транзакция короткая: по умолчанию действует лимит в пять секунд и 10 МБ изменённых данных, а длинные операции нужно разбивать на части.
import fdb
fdb.api_version(730)
db = fdb.open()
key = fdb.tuple.pack(("user", 42))
@fdb.transactional
def save(tr, key, value):
tr[key] = value
save(db, key, "Анна".encode("utf-8"))
print(db[key].decode("utf-8"))
Слой tuple превращает кортеж в ключ с сохранением порядка, а слой directory даёт именованные пространства. Для горячих ключей добавляйте случайный префикс или используйте хеширование: FoundationDB любит равномерное распределение, а не последовательные идентификаторы. Клиент повторяет транзакцию при конфликте, поэтому функция не должна иметь побочных эффектов вне базы: отправка письма или запрос к внешнему API внутри блока приведут к дублям.
Чтение внутри транзакции видит собственные записи, а снимок данных остаётся согласованным. Если операция только читает, не добавляйте в неё записи: лишние конфликтные диапазоны увеличивают число повторов.
Установка и создание базы
Пакеты foundationdb-clients и foundationdb-server ставятся из официального репозитория. После установки служба foundationdb управляет процессами через fdbmonitor. Файл /etc/foundationdb/fdb.cluster содержит описание кластера, а конфигурация процессов лежит в /etc/foundationdb/foundationdb.conf.
sudo apt install foundationdb-clients foundationdb-server
sudo systemctl enable --now foundationdb
sudo fdbcli --exec "configure new single ssd"
sudo fdbcli --exec "status minimal"
Команда configure new инициализирует пустую базу и уничтожает прежние данные, поэтому её выполняют только на новом кластере. Для отказоустойчивой конфигурации из нескольких узлов используют режимы double или triple и указывают тип диска. Перед этим задайте одинаковый кластерный файл на всех машинах.
Кластер и обслуживание
В кластере есть координаторы, transaction servers, storage servers и logs. Координаторы хранят метаданные и выбирают лидера; их число должно быть нечётным. Команда status json отдаёт подробную картину, которую удобно фильтровать через jq.
sudo fdbcli --exec "status json" | jq '.cluster.processes | length'
sudo fdbcli --exec "status details"
sudo fdbcli --exec "exclude 192.0.2.21"
sudo fdbcli --exec "include 192.0.2.21"
Перед обслуживанием узел исключают из кластера, дожидаются перераспределения данных и потом выключают. Возврат делают командой include. Не выводите несколько узлов одновременно: режим double переживёт потерю одной машины, но не большинства.
Диапазоны и прикладные ключи
Чтение диапазона возвращает пары в отсортированном порядке. Внутри транзакции можно делать несколько чтений и записей — они увидят согласованный снимок. Если операция только читает, не добавляйте в неё записи: конфликтные диапазоны увеличивают число повторов.
@fdb.transactional
def list_users(tr, prefix):
start, end = fdb.tuple.range((prefix,))
for key, value in tr.get_range(start, end):
print(fdb.tuple.unpack(key), value.decode("utf-8"))
list_users(db, "user")
Не храните в одном значении мегабайты: крупные объекты выносите в отдельное хранилище, а в базе держите ссылку и метаданные. Так проще соблюдать лимиты и обслуживать кластер.
Резервное копирование
Утилита fdbbackup делает непрерывную резервную копию, а fdbrestore восстанавливает её на другой кластер. Для аварийного переключения между площадками предусмотрен fdbdr. Проверяйте восстановление на тестовом кластере: наличие файлов бэкапа ещё не гарантирует успешный возврат данных.
sudo -u foundationdb fdbbackup start -z -d file:///srv/fdb-backup
sudo -u foundationdb fdbbackup status
sudo -u foundationdb fdbrestore start -r file:///srv/fdb-backup/<timestamp> --dest-cluster-file /etc/foundationdb/fdb.cluster -w
sudo -u foundationdb fdbbackup discontinue
При восстановлении из локального каталога указывают не базовый путь, а конкретный подкаталог, созданный заданием; его имя покажет fdbbackup list -b file:///srv/fdb-backup. Для восстановления на момент времени добавляют подходящую отметку, а после завершения проверяют status minimal и целостность приложения, а не только код возврата. Резервную копию удобно хранить отдельно, но путь file:// должен быть доступен процессу foundationdb для записи.
Эксплуатация и диагностика
Следите за свободным местом, задержками и синхронизацией времени. FoundationDB чувствительна к рассинхронизации часов и нехватке файловых дескрипторов. Журналы процессов лежат в /var/log/foundationdb, сводные сообщения — в journald.
sudo journalctl -u foundationdb -n 100 --no-pager
df -h /var/lib/foundationdb
sudo chronyc tracking
sudo fdbcli --exec "status minimal"
Перед обновлением проверьте совместимость клиентских библиотек и серверной части. Клиент с неверным номером API не подключится, даже если сеть и кластерный файл настроены правильно. Сначала обновляйте драйверы и только затем прикладные сервисы, чтобы не получить несовместимый протокол на живой системе.
status minimalпоказывает доступность и режим репликации.- Рост
data lagуказывает на медленный диск или перегрузку сети. - Ошибки клиента при конфликте — норма; проверьте, что транзакция повторяется.
- После замены диска убедитесь, что узел вернулся в
includeи данные перераспределились.
Когда выбирать FoundationDB
База хорошо подходит для систем с большим числом коротких транзакций, строгими требованиями к согласованности и собственной моделью данных. Отдельно оцените объём значений и профиль нагрузки: небольшие записи и частые операции переносятся легче, чем редкие многомегабайтные обновления. Она требует дисциплины в проектировании ключей и не заменяет аналитическое хранилище: сложные JOIN и отчёты поверх неё строят отдельно. Если нужен обычный SQL и знакомые инструменты, проще взять PostgreSQL; если нужна именно транзакционная основа для своего слоя, FoundationDB даёт предсказуемое поведение.
Итог
FoundationDB — это низкоуровневый, но надёжный фундамент для распределённых приложений. Начните с одного узла, создайте базу, проверьте status, затем добавьте репликацию и резервное копирование. Ключевые правила: короткие идемпотентные транзакции, равномерные ключи, контроль часов и регулярная проверка восстановления.