Привет, Хабр!
На связи Евгений Ярош, руководитель направления СУБД «Инфосистемы Джет».
Любая распределенная база данных обещает две вещи: неограниченное масштабирование и высочайшую отказоустойчивость. СУБД от Яндекса – YDB - изначально имеет распределенную архитектуру, где шардирование и восстановление работают «из коробки» и без downtime. Большинство обзоров YDB, которые я изучил, делятся на два типа:
Вендорские презентации: «что YDB умеет».
Академические разборы: «как YDB устроена внутри».
Мне не хватило третьего — практического руководства глазами инженера ИТ-инфраструктуры. Поэтому мы развернули тестовый кластер и начали ломать его в самых ожидаемых сценариях.
В статье я расскажу о результатах тестирования: как YDB разворачивается «в бою», что происходит при сбоях, как работает восстановление, как ведет себя кластер под нагрузкой, с какими сюрпризами столкнется команда, которая будет ее администрировать. Весь анализ — с фокусом на уменьшение операционных затрат и повышение надежности.
Что же такое YDB?
Это гибридная система управления базами данных, поддерживающая SQL и API для работы с данными в NoSQL-стиле. Для тех, кто знаком с CAP-теоремой, стоит обратить внимание на то, что YDB относится к классу CP. При сетевом разделении между узлами система может временно стать недоступной, но гарантирует согласованность данных.
YDB ориентирована на высокую отказоустойчивость, горизонтальное масштабирование без ограничений как по вычислительной нагрузке, так и по хранению. Это позиционирует СУБД от Яндекса как наиболее подходящее решение для сервисов, где важны:
высокая доступность данных (до 99.99%);
масштабируемость вычислений (при чем как в большую, так и в меньшую сторону);
гибкость модели данных;
строгая поддержка ACID-транзакций.
Версии YDB
На данный момент существует две версии YDB:
OpenSource — свободно распространяемая версия, которую можно скачать с официального сайта ydb.tech
Корпоративная версия — коммерческая реализация с поддержкой вендора или провайдера поддержки, которая доступна на сайте ясубд.рф .
Обе версии до недавнего времени были практически идентичны. Однако на текущий момент появляются функции, доступные только в корпоративной версии. Судя по роадмапу, в будущем будет больше специализированных функций именно для корпоративных ИТ-инфраструктур.
Важные различия, на которые стоит обратить внимание:
OpenSource-версия требует наличия библиотеки glibc 2.30+. Но, например, в репозитории Astra она старее, и поэтому несовместима с Astra Linux.
В ближайших релизах корпоративной версии анонсируются отличия от OpenSource: расширенный административный интерфейс, дополнительная архитектура системы, ориентированная на два ЦОДа; инкрементальное резервное копирование.
В остальном отличия пока несущественные. С первого взгляда даже кажется, что оба сайта с разными версиями идентичны.
Установка YDB
Сейчас YDB можно развернуть в трех основных архитектурных вариантах:
block-4-2 (отказоустойчивый кластер в одном ЦОДе);
mirror-3-dc (катастрофоустойчивый кластер в трех ЦОДах);
none (одиночная ознакомительная инсталляция, например, в докере).
Кластерные архитектуры принципиально отличаются по количеству нод, числу копий данных и модели отказа.

Существует еще один подвид упрощенной архитектуры mirror-3-dc, в которой используются только 3 сервера, по одному в каждом ЦОД. В нем область отказа фактически равна домену отказа. Такую архитектуру, с учетом сниженной надежности относительно полноценного кластера, можно использовать не только для тестов.
Кроме этого, в новой версии ожидается вариант архитектуры на 2 ЦОДа в корпоративной версии с дополнительным слоем управления над имеющимися уровнями.
Ознакомительный вариант установки в виде докер-контейнера отбрасываем сразу. С точки зрения ИТ-инфраструктуры для качественной оценки нужна инсталляция с отказоустойчивостью. Из предлагаемых архитектурных вариантов дл�� нашей инсталляции был выбран упрощенный кластер mirror-3-dc. Это оптимальный вариант по требуемым ресурсам, обладающий отказоустойчивостью.
Стоит отдельно сказать про ресурсы. Требования для работы YDB довольно солидные. Например, для хранения в кластере на три ЦОДа обязательно наличие не менее девяти дисков. При этом неважно, сколько будет серверов — 3 или 9. Минимальное требование для одного диска — 80 Гб. На меньшем объеме кластер может просто не запуститься. Но это не значит, что все выданное по минимальному объему уйдет только на работу самой СУБД.
В части CPU тоже не стоит пробовать запускаться менее чем на 16 ядрах. В нашем жестоком ИТ-мире чудес не бывает. За автоматизацию, сжатие и шифрование приходится платить накладными расходами на вычислительные мощности.
Еще один интересный момент в архитектуре YDB — отделение слоя хранения данных от слоя вычислений. Узлы хранения (storage nodes) отвечают за первый слой, а узлы базы данных (database nodes) — за вычислительный. Это позволяет, к примеру, разносить такие элементы по разным серверам, отдельно добавлять объемы в слой хранения, наращивать производительность на слое вычисления. Слои обеспечены разными процессами, каждый из которых можно запускать не в единственном экземпляре на одном сервере, главное — чтобы хватало ресурсов. Например, если на каждом сервере кластера Block-4-2 будет запущено по одному процессу хранения и по два вычислительной обработки, то схематично это правильней отобразить вот так:

СУБД YDB можно развернуть несколькими способами:
вручную;
через Ansible-скрипты;
в Kubernetes.
В целом процесс установки подробно описан в документации. Он одинаково применим как к OpenSource, так и к корпоративной версии. Стоит обратить внимание на актуальность. Сейчас документация для Open Source версии может обновляться чаще, поэтому при работе с корпоративным дистрибутивом также рекомендуется проверять соответствующие разделы.
Для первичной инсталляции мы рекомендуем пройти установку в ручном режиме, чтобы лучше понимать основные требования к работе системы. Установка несложная. СУБД запускается одним бинарным файлом с конфигурацией, и все действия по инсталляции заключаются в его правильном расположении, обеспечении нужной учетной записью с правами, корректными параметрами конфигурационного файла и автоматизации запуска сервиса. Если идти по пошаговому гайду, сделать что-то неправильно можно только из-за невнимательности.
Стенд собирался на корпоративной версии, в автоматическом режиме скриптами. Установка с помощью ansible-скриптов похожа на ручную установку и в целом проходит так же гладко. Однако при установке на Astra 1.8 мне пришлось самостоятельно прописать эту ОС в скриптах, потому что на тот момент была описана только версия 1.7. Поскольку используемые технологии немного сложнее, чем просто копирование файлов и назначение прав, кажется, что вероятность человеческих ошибок при настройке окружения для запуска скриптов немного выше. Хотя, как говорится, на вкус и цвет все фломастеры разные.
После установки визуальных различий между версиями не обнаружилось. Графический интерфейс выглядит одинаково.

Графический интерфейс позволяет решить большинство задач обслуживания кластера в части управления и мониторинга. Чтобы упростить мониторинг, метрики можно отдавать в формате Prometheus и подключить их к Grafana — получится знакомый и «корпоративный» дашборд.
Помимо графического интерфейса YDB предоставляет консольные утилиты, основная из которых — ydbcli. Это основной инструмент командной строки, который позволяет:
подключаться к базам,
выполнять SQL-запросы,
управлять таблицами и схемами,
выполнять бэкапы,
проводить нагрузочное тестирование.
Помимо ydb cli, существуют и другие утилиты. Например, YDB DSTool используется для управления дисковой подсистемой, а ydbops — для поочередной перезагрузки нод кластера без остановки базы данных.
Тестирование отказоустойчивости YDB на синтетике
Чтобы лучше понять поведение YDB в условиях внештатных ситуаций, проведем серию практических тестов на собранном стенде. Сценарии подразумевают наличие постоянной нагрузки на тестовую базу данных с одновременными преднамеренными и не очень изменениями в кластере YDB.
Описание стенда:
Количество нод: 3 сервера 24 vCPU, 16 Gb RAM, 3х100 Gb SSD под данные.
Архитектура: mirror-3dc.
Генератор нагрузки: ydb-cli.
Прокси-балансировщик: HAProxy.
Балансировщик установлен на той же ВМ, что и генератор нагрузки, но в целом это не принципиально для текста. По словам вендора, HAProxy не становится узким местом ни по нагрузке, ни по отказоустойчивости. Он нужен только для того, чтобы получить от кластера список нод, обрабатывающих запросы к конкретной базе, а дальше обращения идут напрямую, уже без участи прокси.
Впрочем, вместо HAProxy можно использовать и dns-round robin. Главное — первичный запрос должен попадать на работающий сервер. Обычно это постоянные узлы хранения, которые редко меняются, в отличие от динамических
Стенд размещен в среде виртуализации. Вендор такой вариант не рекомендует, но под рукой не нашлось лишних физических серверов. Поэтому тестируем на том, что есть.

Сценарии тестирования
Сценарий 1-1: Отказ ноды СУБД
Отказ сервера в кластере — сценарий, на который хотелось посмотреть в первую очередь.
Запросы генерировать будем через ydb cli, в которой есть типовые сценарии генерации нагрузки. Для наших тестов возьмем нагрузку типа «магазин» (stock). Для начала в чистой базе создадим таблички с данными магазина:
~$ ydb workload stock init --products 500000 --quantity 5000 --orders 10000
При этом автопартиционирование будет включено по умолчанию.
А при запуске самой нагрузки будем задавать подключение в 20 потоков в течение 5 минут. В этом сценарии на каждом из трех серверов был запущен по одному узлу хранения и одному узлу базы данных.
Команда запуска нагрузки через cli следующая:
~$ydb workload stock run rand-user-hist --seconds 300 --threads 30 --limit 10000 --print-timestamp
В качестве точки подключения к БД использовался профиль через HAProxy.
~$ ydb config profile get ydb-by-haproxy
endpoint: grpcs://astra-ydb-PROMETHEUS:50051
database: /Root/test_db
static-credentials
user: root
password file: /opt/ydb-manage/ydb-ansible-examples/current-ydb/ansible_vaul t_password_file
ca-file: /opt/ydb-manage/ydb-ansible-examples/TLS/certs/ca.crt
Без нагрузки консоль мониторинга базы показывала следующую картинку.







В целом, если посмотреть со стороны операционной системы, то там видно то же самое:



Поскольку стенд находился в общей среде виртуализации, тесты запускались несколько раз, чтобы точно убедиться в стабильности и воспроизводимости результатов.
Примерно через минуту после запуска генератора нагрузок консоль обычно выглядела следующим образом:

Видно, что базу хорошо нагружаем. По собранной статистике генератора по результатам трех запусков получаем следующую картину по количеству транзакций в секунду.



Теперь повторим тестирование, но во время нашей пятиминутной нагрузки отключим один самый нагруженный сервер по питанию. Проверим, как будет реагировать кластер.
При отключении сервера консоль показывает примерно одинаковую картину:

Если посмотреть на график нагрузки во время эксперимента (он проводился трижды, и каждый раз отключалась самая нагруженная нода), то получаем следующую картину:

В первом тесте в момент отключения, а это было выполнено в середине теста, самой нагруженной оказалась первая нода. На ней же выполнялись системные процессы.

При повторном запуске опять первая нода была самой нагруженной, но системные процессы СУБД были на другом сервере, но просадка в середине теста оказалась примерно такой же, до 6000 trx/s.

При третьем запуске самой нагруженной нодой оказалась третья. Она не несла на себе системной нагрузки.
Из графиков видно, что транзакции выполнялись каждую секунду, хотя их количество немного колебалось, в момент отключения в серединах тестов отказов в работе не было, но было снижение общего количества обрабатываемых транзакций.
В момент отключения серверов (примерно на 150-й секунде) поток транзакций не прерывался, независимо от того, выполнялись ли на отключаемой ноде системные процессы кластера.
Помимо числа операций генератор фиксировал количество ошибок и повторных запросов. При таком тестировании количество ошибок, которые получил клиент при запросах, не превышало 20, а количество отправленных повторов — 30.
Что получаем в итоге? Падение ноды с системными процессами или без них никак не влияет на обслуживание запросов клиентов. Но при недостатке производительности количество обрабатываемых запросов может снизиться.
Сценарий 1-2: Отказ HAProxy при активной нагрузке
Скрытый текст
В этом сценарии хотелось убедиться, точно ли наш балансировщик никак не влияет на нагрузку. Для этой проверки запустим нагрузку (как и в первом сценарии), но в моменте ее выполнения выключим сервис HAProxy. Сделаем это примерно на середине теста и посмотрим, как это повлияет на БД.
Одного теста, думаю, будет достаточно:

Хотя HAProxy перестал работать, клиентская часть смогла продолжить функционировать с найденными при первом подключении нодами кластера. Это позволило продолжить выполнение запросов.
Это неплохо, но сразу же возник закономерный вопрос: как клиент отреагирует на изменение количества нод после выключения HAProxy?
Логично предположить, что если их количество уменьшится, то запросы будут распределяться по оставшимся. Возможно, ошибок будет больше.
А что, если нод, наоборот, прибавится? Будет ли наш клиент-генератор в процессе распределять нагрузку по нодам, которых не было при старте запросов?
Запускаем нагрузку и проверяем консоль СУБД на старте нагрузки:

Теперь отключаем HAProxy. Через некоторое время запускаем еще три динамические ноды для БД и получаем:

Появившиеся дополнительные вычислительные ноды не получили свою порцию нагрузки, хотя кластер и распределил размещение каких-то блоков данных на них.
Тестирование отказоустойчивости YDB на реальной БД
Уже под конец тестирования, когда статья была почти готова, мы поняли, что нам этого недостаточно. Синтетическая нагрузка хорошо показывает базовое поведение системы, но все же остается синтетикой. Она не отражает всех нюансов реальной работы. Нам хотелось посмотреть, как YDB поведет себя под реальной нагрузкой.
Чтобы получить такую картину, мы решили провести второй заход тестирования уже на серьезном банковском приложении. Для этого выбрали систему банковского процессинга «Сигма» от компании Лектон.
Второй стенд был развернут в полноценной архитектуре mirror-3-dc с девятью серверами СУБД. Для первичного подключения, как и раньше, использовался HAProxy.
В базе данных предварительно были созданы 100 000 клиентов со своими картами МИР. Нагрузка генерировалась равномерно и случайно по всему пулу карт — выполнялось около 300 операций оплаты в секунду, что соответствует уровню среднего банка.
Каждая операция оплаты включала примерно шесть запросов SELECT, три INSERT и два UPDATE, не считая обновлений индексов. В итоге на уровне базы данных это означало обработку нескольких тысяч запросов в секунду — в нашем случае около 4 500 операций на 300 бизнес-операций.

Для анализа работы приложения использовались метрики, собранные Victoria Metrics и отображаемые в Grafana:
количество операций, выполненных системой;
отклики на операции для воркеров приложения в трех процентилях: 50, 90 и 99.
Так как на втором стенде была развернута полноценная архитектура, была возможность проверить различия между сценариями отказа отдельно взятого сервера и целого ЦОД. К слову, такую демонстрацию я проводил на конференции IT Elements 2025 в режиме реального времени. Посмотреть можно тут.
Сценарий 2-1: Отключение отдельно взятого сервера при работающем процессинге
Скрытый текст
Сценарий в целом аналогичен тесту «1-1», за исключением того, что теперь с базой работает продуктивное приложение. Мы можем оценить, как оно видит свою работу с СУБД со своей стороны.
В качестве «жертвы» для отключения подбирался самый загруженный по CPU сервер. Иначе в эксперименте не было бы смысла, верно?
В результате картина отключения самой нагруженной ноды со стороны приложения выглядела следующим образом:

Система «просела» в производительности на пару минут, затем перераспределила нагрузку между серверами. Ресурсов в кластере СУБД было достаточно, а нагрузка со стороны процессинга составляла те самые 300 бизнес-операций в секунду.
В момент отказа одного из серверов очередь необработанных операций начала расти. После перебалансировки кластера на короткий промежуток времени производительность даже немного превысила значение в 300 операций. Это была обработка накопившейся очереди.
По метрикам видно, что на этом этапе время отклика от СУБД стало больше, чем надо. Очевидно, на отключенном сервере были открыты сессии и выполнялись операции. Из-за этого воркеры ждали либо завершения, либо сброса по таймауту для продолжения работы. В случае таймаута сессия инициировалась заново, но уже с другим сервером.
Со стороны обработки транзакций также наблюдалась небольшая кратковременная деградация:

Сценарий 2-1: Отключение всех серверов в одном «ЦОД»
Сценарием с отключением отдельного взятого сервера уже никого не удивить. Любой маломальский кластер отработает failover в автоматическом режиме. Если база не очень большая и нагруженная, возможно, приложение этого и не заметит. Хотя, в отличие от распределенной СУБД, в монолитной системе при переключении нагрузка проседает полностью — пусть и ненадолго.
Совсем другое дело — падение всего ЦОД, то есть сценарий DR. Мало кто может без опаски делать автоматический failover между ЦОД — высокий риск сбоя сети может привести к непреднамеренному переключению, когда в этом нет необходимости. Поэтому автоматическая отработка такого сценария выглядит очень любопытной.
После отключения трех серверов одной области доступности получаем следующую картину со стороны приложения:

В данном случае влияние на приложение хоть и оказалось сильнее, чем при отказе отдельно взятого сервера, но проблема длилась не более пары минут. После этого система обработала все наколенные операции и продолжила функционировать в обычном режиме.
Со стороны СУБД количество операций на время также значительно снизилось:

Поскольку демонстрация (доступная в записи) была не первой, я могу отметить повторяемость сценария. Подобное падение нагрузки — это худший из зафиксированных вариантов при отключении всей зоны доступности.
Например, во время первой демонстрации результат отключения ЦОД выглядел так:

При кратком анализе причин различий в просадке производительности были найдены неравномерности нагрузки на отдельные шарды таблиц базы данных. Команда разработки также подтвердила, что на момент экспериментов адаптация «Сигмы» еще не была завершена. Из-за неравномерного первичного ключа нагрузка распределялась по одной из самых «тяжелых» таблиц неравномерно. Тесты стали отправной точкой для взаимодействия. В будущем мы планируем повторить тестирование, чтобы оценить прогресс в оптимизации и увидеть, как доработки повлияют на результаты.
Поэтому неплановые отключения отдельных серверов могли затрагивать наиболее нагруженные фрагменты таблиц. Их одновременное отключение приводило к заметным, но кратковременным просадкам производительности.
Что YDB дает инфре (чего не могут дать PostgreSQL и Oracle)
Тестирование от синтетики до процессинга показало, что YDB способна обеспечить безотказную работу базы данных даже в сложных условиях (при отказе отдельных серверов или целого ЦОД) и даже при потере нескольких узлов. Это не требует ручной настройки, создания собственного шардига или внешних систем переключения. В этом случае катастрофоустойчивость – фундаментальная часть архитектуры. И это особенно заметно в сравнении с PostgreSQL и Oracle.
Чем YDB отличается от PostgreSQL и Oracle
Горизонтальное масштабирование. В YDB оно встроено в архитектуру, это изначально распределенная система с автоматической балансировкой шардов и перераспределением нагрузки. PostgreSQL не умеет расти горизонтально. Любые попытки распределить данные требуют логической репликации или самодельного шардинга. Oracle обеспечивает масштабирование более предсказуемо, но стоимость такого решения очень высокая.
Отказоустойчивость без простоев и переключений. У YDB отказ ноды или зоны доступности — штатная ситуация. Если из строя выходит сервер или целая площадка, система продолжает работать. Приложение не нужно переподключать. Для бизнеса это означает, что отказ одного сервера не превращается в инцидент — система сама «выровняется» и продолжит обслуживать запросы. В PostgreSQL обновления, переключения на резервный сервер и другие операции связаны с остановками обслуживания на переключение «мастера», которое может занять значительно время, в зависимости от условий работы. Нужно подождать, пока база перестроится, переключится или освободит ресурсы. Что в целом нормальная ситуация для монолитной СУБД.
Современная архитектура. PostgreSQL и Oracle эволюционировали десятилетиями и несут архитектуру, заложенную в 90-х. Поэтому все современные функции, от репликации до кластеризации, добавлялись поверх. YDB изначально проектировали как распределенную систему
После тестирования на боевой нагрузке становится очевидно, что YDB значительно снижает инженерную сложность обслуживания БД. Да, особенности распределенных систем остаются, и проектирование схемы данных важно. Но объём рутинной операционной работы, которую сегодня приходится выполнять командам PostgreSQL/Oracle, в YDB значительно меньше. Это не замена на уровне «давайте смигрируем все», но это современная альтернатива.
Разумеется, полностью забыть о распределенной природе базы не получится, останутся накладные расходы на обработку распределенных транзакций, более серьезные требования к аппаратным характеристикам серверов и сети передачи данных. Но мне кажется, оно стоит того, чтобы ваша продуктивная система работала без отказов и могла обслуживаться «на лету».