YugabyteDB — распределённая SQL-СУБД, которая притворяется PostgreSQL: тот же протокол, тот же клиент ysqlsh, знакомый синтаксис. Внутри — собственный слой хранения DocDB на RocksDB с репликацией Raft, поэтому кластер переживает потерю узла или зоны и масштабируется горизонтально. Для приложения это выглядит как обычный PostgreSQL на нестандартном порту 5433.
Архитектура
Кластер состоит из YB-Master и YB-TServer. Мастера хранят метаданные, распределяют таблеты и следят за схемой; таблет — единица шардирования, у которой есть лидер и реплики в группе Raft. TServer обслуживает таблеты и выполняет запросы. Порты по умолчанию: 7000 у мастера, 9000 у tserver, 5433 у YSQL, 9042 у YCQL.
YSQL — слой совместимости с PostgreSQL: разбор, планировщик и каталог свои, но протокол и большинство конструкций знакомы. Важно понимать цену: запрос через несколько таблетов идёт по сети и требует координации, поэтому схема ключей влияет на производительность сильнее, чем в одиночном PostgreSQL.
Запись попадает к лидеру таблета, реплицируется на последователей и подтверждается после кворума. Чтение по умолчанию обслуживает лидер, поэтому задержка зависит от сети между узлами. Отсюда практическое правило: узлы ставят в одну сеть с малой задержкой, а синхронизацию времени настраивают обязательно — Raft чувствителен к расхождению часов.
Локальный стенд
Быстрее всего поднять один узел в Docker. Для эксперимента хватит трёх портов: YSQL, YCQL и веб-интерфейс.
docker run -d --name yugabyte \
-p 5433:5433 -p 9042:9042 -p 15433:15433 \
yugabytedb/yugabyte:latest bin/yugabyted start --background=false
Проверка состояния и подключение:
docker exec -it yugabyte bin/yugabyted status
docker exec -it yugabyte bin/ysqlsh -h 127.0.0.1 -p 5433 -U yugabyte
curl -s http://127.0.0.1:15433 | head
Веб-интерфейс показывает узлы, таблеты и отставание реплик. Если ysqlsh не подключается, проверьте, что контейнер успел пройти инициализацию: на слабой машине это занимает десятки секунд.
Кластер из трёх узлов
Для реальной отказоустойчивости нужно минимум три узла и replication factor 3. Первый узел стартует отдельно, остальные присоединяются к нему через —join; каталог данных задаётся явно, чтобы не потерять состояние при обновлении.
./bin/yugabyted start --advertise_address=10.0.0.11 --base_dir=/data/yb --fault_tolerance=zone
./bin/yugabyted start --advertise_address=10.0.0.12 --join=10.0.0.11 --base_dir=/data/yb --fault_tolerance=zone
./bin/yugabyted start --advertise_address=10.0.0.13 --join=10.0.0.11 --base_dir=/data/yb --fault_tolerance=zone
./bin/yugabyted status
Проверить состав кластера и таблеты можно через yb-admin. Адреса мастеров перечисляются через запятую, порт — 7100. Если replication factor остался равным единице, задайте его явно командой configure data_placement с ключами —rf=3 и —fault_tolerance=zone.
./bin/yb-admin --master_addresses 10.0.0.11:7100,10.0.0.12:7100,10.0.0.13:7100 list_all_masters
./bin/yb-admin --master_addresses 10.0.0.11:7100,10.0.0.12:7100,10.0.0.13:7100 list_all_tablet_servers
Не размещайте узлы в одной зоне, если заявляете отказоустойчивость: Raft переживёт потерю меньшинства, но не потерю двух из трёх. Для мультирегионального варианта задержка записи вырастет — это плата за синхронную репликацию.
Между узлами должны быть открыты 7100 для мастеров и 9100 для tserver, а также порты RPC. Проверьте синхронизацию времени через chronyc tracking: расхождение часов приводит к ошибкам выборов лидера и странным таймаутам. Перед запуском полезно прогнать сетевой тест между всеми парами узлов.
Схема и ключи
Главное решение при проектировании — первичный ключ. Хешированный ключ равномерно разносит записи, диапазонный удобен для выборок по времени. Композитный ключ позволяет совместить оба подхода.
CREATE TABLE orders (
customer_id bigint NOT NULL,
id bigserial,
created_at timestamptz NOT NULL DEFAULT now(),
total numeric(12,2),
PRIMARY KEY (customer_id HASH, id ASC)
);
CREATE INDEX orders_created_idx ON orders (created_at DESC);
Проверить распределение можно через yb_hash_code. Если все строки попали в один шард, ключ выбран неудачно — горячая таблетка станет узким местом.
SELECT yb_hash_code(customer_id) % 6 AS shard, count(*)
FROM orders GROUP BY 1 ORDER BY 1;
EXPLAIN показывает распределённый план: обмен между узлами говорит о том, что запрос собирает данные с нескольких таблетов. Это нормально для аналитики и плохо для точечных операций в цикле.
Эксплуатация и бэкапы
Логический дамп переносим между версиями, снапшот быстрее и требует совместимого кластера. Для регулярной защиты достаточно дампа схемы и данных плюс проверки восстановления на отдельном стенде. Дамп, который не разворачивается, нельзя считать резервной копией, поэтому фиксируйте и время восстановления.
./bin/ysql_dump --host=10.0.0.11 --port=5433 --username=yugabyte --dbname=app -f app.sql
./bin/ysql_dumpall --host=10.0.0.11 --port=5433 --username=yugabyte -f all.sql
./bin/ysqlsh -h 10.0.0.11 -p 5433 -U yugabyte -d app -f app.sql
./bin/ysql_dump --host=10.0.0.11 --port=5433 --username=yugabyte --dbname=app --schema-only -f schema.sql
Метрики отдаются в формате Prometheus: tserver на 9000, мастер на 7000. Минимальный набор для наблюдения — задержка записи, число незавершённых Raft-операций, отставание реплик и свободное место.
curl -s http://10.0.0.11:9000/metrics | grep -E 'raft|latency|disk'
curl -s http://10.0.0.11:7000/metrics | grep -E 'master|tablet'
Обновляйте узлы по одному и дожидайтесь восстановления реплик. Для планового обслуживания полезно сначала проверить статус, затем остановить узел, затем вернуть его и убедиться, что лидеры перераспределились.
Совместимость и подводные камни
YSQL покрывает основной SQL, транзакции и знакомые типы, но это не PostgreSQL под другой вывеской. Часть расширений и административных функций недоступна, а поведение некоторых запросов отличается из-за распределённой природы. Перед миграцией прогоняйте реальные запросы и проверяйте матрицу совместимости для своей версии.
- проверить расширения и ORM;
- измерить задержку на реальных запросах;
- настроить пул соединений;
- протестировать потерю узла.
Длинные транзакции, блокировки на DDL и запросы без ключа шардирования — главные источники проблем. Пулы соединений обязательны: каждый бэкенд YSQL занимает память, а приложение с сотнями воркеров легко упрётся в лимит.
Не ждите, что аналитический запрос на миллиард строк будет быстрым «как в специализированном хранилище»: YugabyteDB оптимизирован под транзакционную нагрузку с предсказуемой задержкой. Отдельно проверьте поведение ORM: некоторые конструкции генерируют запросы без ключа шардирования и незаметно превращаются в полный скан.
Итог
YugabyteDB даёт знакомый PostgreSQL-интерфейс и горизонтальное масштабирование, но требует осознанного выбора ключей и дисциплины эксплуатации. Начните с локального стенда, проверьте свой набор запросов, затем поднимите три узла и настройте мониторинг.
Ключевые проверки перед продакшеном: replication factor 3, разнесение по зонам, тест потери узла, обратимое восстановление из дампа и контроль задержки между регионами.