Москва: проверенные б/у ноутбуки с гарантией и проверкой перед оплатой
+7 906 722-94-45

Главная → Статьи → NewSQL: распределённые SQL-базы и их компромиссы

NewSQL: SQL-семантика поверх распределённого хранилища

NewSQL: CockroachDB, TiDB и YugabyteDB, консенсус Raft, шардирование и транзакции, отличия от шардированного PostgreSQL.

Прямой ответ

NewSQL — класс систем, которые сочетают SQL и транзакционные гарантии реляционных СУБД с горизонтальным масштабированием, характерным для NoSQL. Представители: CockroachDB, TiDB, YugabyteDB, а также Spanner как родоначальник направления.

Общая архитектура:

  1. Данные разбиваются на диапазоны (range в CockroachDB, region в TiDB) по первичному ключу.
  2. Каждый диапазон реплицируется на несколько узлов; согласованность реплик обеспечивает консенсус-протокол, обычно Raft — см. алгоритм Raft.
  3. SQL-слой разбирает запрос, строит план и координирует выполнение на нескольких узлах.
  4. Транзакции выполняются распределённо с использованием меток времени и многоверсионности.

Что это даёт на практике:

  • Масштабирование добавлением узлов вместо вертикального роста одной машины.
  • Отсутствие единой точки отказа: отказ узла не останавливает работу, диапазоны переходят к другим репликам.
  • Сохранение SQL: существующие запросы и ORM работают с минимальными изменениями.
  • Автоматическое шардирование: разработчику не нужно выбирать ключ шардирования — о сложностях ручного выбора в статье про шардирование.

Цена такого устройства:

Аспект Влияние
Задержка записи Выше из-за консенсуса между репликами
Распределённая транзакция Дороже локальной: несколько раундов обмена
Соединения между диапазонами Требуют координации между узлами
Последовательности и автоинкремент Могут выдавать значения с пропусками
Географическое распределение Задержка определяется расстоянием между центрами

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

-- CockroachDB: привычный SQL, данные распределены автоматически
CREATE TABLE orders (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    customer_id UUID NOT NULL,
    created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
    total DECIMAL(12,2) NOT NULL
);
-- локальность реплик можно задать явно
ALTER TABLE orders CONFIGURE ZONE USING num_replicas = 3;

Практика: когда переход оправдан

Признаки, что вертикальное масштабирование исчерпано:

  1. Объём данных или нагрузка записи превышают возможности одной машины, и рост продолжается.
  2. Ручное шардирование уже реализовано и стало основным источником сложности и ошибок.
  3. Требуется доступность при отказе целой зоны или региона.

Признаки, что переход преждевременен:

  1. Данные помещаются на одной машине с запасом на годы вперёд.
  2. Основные запросы — аналитические агрегации; для них подходит колоночное хранилище.
  3. Команда не готова эксплуатировать кластер: мониторинг, обновления, восстановление.

Рекомендации:

  1. Проектируйте первичный ключ под распределение. Монотонно растущий ключ создаёт горячий диапазон на одном узле. Практика — UUID или составной ключ с хорошим распределением.
  2. Держите связанные данные вместе. Запросы, постоянно соединяющие две таблицы, выигрывают от одинакового ключа локальности; иначе каждый запрос становится распределённым.
  3. Измеряйте задержку до перехода. Консенсус добавляет миллисекунды к каждой записи. Для сценариев с тысячами записей в секунду на одну сущность это может быть критично.
  4. Проверяйте совместимость SQL. Совместимость с PostgreSQL или MySQL высока, но не полна: отдельные конструкции, расширения и типы могут отсутствовать.
  5. Планируйте восстановление. Распределённая система не отменяет ошибок приложения: логическое повреждение данных replicated на все реплики. Резервные копии остаются обязательными.

Практический сценарий: оценка перехода с шардированного PostgreSQL

Контекст: сервис работал на PostgreSQL с ручным шардированием по 16 базам. Добавление шарда требовало недели работы и остановки части операций.

  1. Анализ запросов. 78 % запросов обращались к данным одного клиента, 14 % требовали соединения данных двух таблиц по ключу клиента, 8 % — аналитические агрегации по всему набору.
  2. Прототип. Развернули CockroachDB, перенесли схему и прогнали типовые запросы на копии данных объёмом 2 ТБ.
  3. Результаты измерения. Запросы по ключу клиента: p95 вырос с 4 до 9 мс. Записи: p95 вырос с 5 до 18 мс из-за консенсуса. Аналитические агрегации: медленнее в 3–6 раз, их решили оставить в хранилище.
  4. Решение. Переход признан оправданным: рост нагрузки требовал добавления шардов каждые четыре месяца, а задержка в пределах 20 мс для сценариев сервиса допустима. Аналитику вывели в отдельный контур.
  5. Что учли дополнительно. Перевели первичный ключ на UUID, чтобы избежать горячего диапазона; настроили локальность реплик по регионам; оставили резервное копирование, потому что консенсус не защищает от логических ошибок.

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

FAQ

Чем NewSQL отличается от шардированной реляционной базы? Шардирование выполняется системой автоматически, а транзакции и соединения работают поверх распределённого хранилища. При ручном шардировании эти задачи решает приложение, и распределённая транзакция обычно не поддерживается.

Заменяет ли NewSQL аналитическое хранилище? Нет. Массовые агрегации по всему набору данных эффективнее выполняются колоночными системами. NewSQL ориентирован на транзакционные нагрузки с точечными запросами.

Что происходит при сетевом разделении? Большинство таких систем выбирает согласованность: диапазоны, оказавшиеся в меньшинстве, перестают принимать запись до восстановления соединения. Чтение в некоторых конфигурациях может продолжаться с устаревших реплик.

Можно ли начать с одной ноды и расти позже? Да, это обычный путь: кластер из одного узла ведёт себя как обычная СУБД, а масштабирование выполняется добавлением узлов без изменения схемы. Такой старт снижает риск, но не отменяет необходимости сразу учитывать распределённость в проектировании ключей.

Источники: CockroachDB docs, TiDB docs, Raft (описание алгоритма) — ссылки в шапке.