awesome-everything EN
↑ Обратно к восхождению

Базы данных

Онлайн-решардинг, 2PC и операционная стоимость шардирования

Суть Онлайн-ребалансировка Citus 11.1+ использует логическую репликацию для суб-секундных пауз при перемещении шарда. Двухфазный commit необходим для кросс-шард транзакций, но несёт риск зависших транзакций. Каждая операционная задача умножается на число шардов.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на senior-высоте — в орбите
◷ 14 min

Кластеру Citus нужно добавить воркер-узел для увеличения мощности. Старый подход требовал окна технического обслуживания: остановить записи, скопировать данные, перезапустить. Citus 11.1 изменил это онлайн-ребалансировщиком, перемещающим шарды пока кластер полностью работает — используя тот же механизм логической репликации, что Postgres использует для обновлений.

Онлайн-решардинг: как это работает

Citus 11.1 (сентябрь 2022) представил non-disruptive онлайн-решардинг. Механизм:

1. Запустить ребалансировщик: SELECT citus_rebalance_start();
2. Планировщик решает: какие шарды перемещаются с воркера A на воркер B для балансировки
3. Для каждого перемещаемого шарда:
   a. Создать шард на целевом воркере (пустой)
   b. Запустить слот логической репликации на источнике для строк этого шарда
   c. Логическая репликация копирует существующие строки на цель, затем стримит изменения
   d. Когда лаг близок к нулю: приостановить записи на шард (~суб-секунда)
   e. Атомарно обновить метаданные карты шардов: шард теперь на цели
   f. Удалить исходный шард
   g. Возобновить записи — теперь маршрутизируются на цель
4. Начать следующий шард (конвейер параллельных перемещений, настраиваемый concurrency)

Профиль производительности:

  • Пауза записи на шард: менее 1 секунды
  • Общее время ребалансировки: масштабируется с объёмом данных (~10–100 МБ/с пропускная способность сети)
  • Влияние на приложение: краткая задержка соединения во время паузы на шард; прозрачно ретраится координатором

Ребалансировщик идемпотентен и возобновляем — если он крашнется в середине перемещения, следующий citus_rebalance_start() продолжит с того места, где остановился, используя состояние pg_stat_subscription.

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

Распределённые транзакции и 2PC

Транзакция, затрагивающая строки на нескольких шардах, требует двухфазного commit (2PC):

-- Один шард: безопасно, обычная транзакция Postgres
BEGIN;
UPDATE orders SET status = 'shipped' WHERE tenant_id = 42 AND order_id = 99;
UPDATE inventory SET qty = qty - 1 WHERE tenant_id = 42 AND sku = 'ABC';
COMMIT;
-- Обе таблицы ко-локированы на одном шарде → однонодовая транзакция

-- Кросс-шард: требует 2PC
BEGIN;
UPDATE orders  SET status = 'refunded' WHERE tenant_id = 42 AND order_id = 99;
UPDATE ledger  SET balance = balance + 100 WHERE account_id = 999;  -- НЕ в рамках клиента
COMMIT;
-- Citus использует PREPARE TRANSACTION + COMMIT PREPARED по обоим шардам

Стоимость 2PC:

  • Задержка: минимум 2 round-trip (фаза prepare + фаза commit); часто больше при учёте clock skew.
  • Пропускная способность: каждый шард держит своё соединение открытым во время фазы prepare — конкуренция при высоком concurrency.
  • In-doubt транзакции: если координатор крашнется между PREPARE TRANSACTION и COMMIT PREPARED, prepared-транзакции сидят в pg_prepared_xacts удерживая блокировки до ручного разрешения. Это режим отказа, который нужно мониторить и иметь runbook для.

Лучшие практики:

  1. Проектировать транзакции как одношардовые: ко-локированные таблицы делают это естественным для операций в рамках клиента.
  2. Предпочитать eventual consistency (outbox pattern, saga) там, где бизнес-логика допускает, вместо распределённого 2PC.
  3. Мониторить pg_prepared_xacts на каждом воркере; алертить на любую строку старше 5 минут; иметь runbook восстановления (COMMIT PREPARED / ROLLBACK PREPARED).

Операционный множитель N×

ОперацияОдин PostgresШардированный (N шардов)
Миграция схемыЗапустить один разCitus автопропагирует DDL от координатора к воркерам; проверить согласованность схемы после миграции на всех воркерах
БэкапыОдин pg_basebackupN координированных бэкапов; все должны целиться в одну логическую точку во времени для согласованного восстановления
Минорное обновление версииОдно rolling updateN rolling updates, координированных; версия Citus должна быть совместимой между координатором и всеми воркерами
VACUUM / bloatОдна конфигурация autovacuumN отдельных процессов autovacuum; каждый шард независимо накапливает мёртвые строки
МониторингОдин дашбордМетрики на шард + агрегаты по кластеру; перекос шардов виден в heatmap

Опытные команды автоматизируют всё через оркестрацию на шард — Ansible с циклом по хостам воркеров, Terraform for_each, Kubernetes операторы — до запуска в продакшне. Без автоматизации операционный персонал линейно масштабируется с числом шардов, что делает операционный налог шардирования конкретным.

Решардинг ключа: дорогой случай

Иногда исходный ключ шарда оказывается неправильным (шардировали по user_id, но 90% запросов нужен org_id). Решардинг по другому ключу требует переписать каждую строку на новое место:

  1. Dual-write + backfill: приложение пишет как в старую, так и в новую схему шардирования; заполнить исторические данные; переключить чтения; удалить старые. Месяцы работы.
  2. Новый параллельный кластер: развернуть новый кластер с правильным ключом, реплицировать через CDC, переключиться. Наиболее гибко; наибольший операционный объём.
  3. Принять стоимость: на практике команды терпят неправильный ключ шарда вместо того, чтобы платить стоимость миграции — сильный аргумент в пользу тщательного выбора с самого начала.

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

Почему это работает

Почему онлайн-решардинг использует логическую репликацию, а не физическую? Физическая репликация (pg_basebackup, streaming) копирует целые страницы данных — вы получили бы данные каждого клиента из исходного шарда, а не только перемещаемого. Логическая репликация копирует изменения на уровне строк (INSERT/UPDATE/DELETE), фильтруя по интересующим строкам. Для перемещения шарда логическая репликация может скопировать ровно строки из перемещаемого шарда и стримить только их изменения до переключения — намного эффективнее и гибче физической копии.

Викторина

Ребалансировщик Citus работает, и координатор крашится в середине перемещения шарда. Что происходит с кластером?

Расставь шаги по порядку

Упорядочьте шаги онлайн-перемещения шарда Citus (с исходного воркера на целевой):

  1. 1 Создать пустой шард на целевом воркере
  2. 2 Запустить слот логической репликации на источнике; скопировать существующие строки на цель
  3. 3 Стримить текущие изменения с источника на цель пока лаг не упадёт почти до нуля
  4. 4 Приостановить записи на этот шард (суб-секунда)
  5. 5 Атомарно обновить метаданные карты шардов: шард теперь указывает на целевой воркер
  6. 6 Возобновить записи — теперь маршрутизируются на цель; удалить исходный шард
Вспомните перед уходом
  1. 01
    Опишите паузу записи на шард во время онлайн-ребалансировки Citus: как долго она длится и почему суб-секундная?
  2. 02
    В чём риск in-doubt транзакции в Citus 2PC и как мониторить и восстанавливаться от него?
  3. 03
    Почему шардирование описывается как 'дверь в одну сторону' и какие операционные последствия из этого следуют?
Итог

Онлайн-ребалансировка Citus 11.1+ использует логическую репликацию для перемещения шардов между воркерами с суб-секундной паузой записи на шард — репетируйте на стейджинге до запуска в продакшне. Кросс-шард транзакции требуют двухфазного commit, который добавляет ~2× задержку, снижает пропускную способность при concurrency и создаёт риск in-doubt-транзакции при краше координатора; мониторьте pg_prepared_xacts и поддерживайте runbook восстановления. Операционный множитель N× означает, что миграции, бэкапы, обновления и VACUUM должны быть автоматизированы на всех шардах до запуска в продакшне — без автоматизации операционный персонал линейно масштабируется с числом шардов. Изменение ключа шарда после запуска — многомесячный проект; проектное решение, принятое в момент горизонтального масштабирования, живёт с командой годами. Шардирование — правильный ответ когда пределы одного Postgres измерены и доказаны — входить намеренно, с автоматизацией, runbook’ами и отработанными операционными процедурами.

Связанные уроки
встречается в258
Продолжить восхождение ↑Sharding: тест с выбором ответа
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.