Кластеризация

Шардинг

Страница Shards — как читать состояние шардов, добавлять и удалять шарды, переносить заказчиков между шардами.

Enterprise

Зачем нужны шарды

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

Шард — это Raft-группа данных плюс заказчики, которые ей принадлежат. Заказчик переносится на шард целиком:

ДанныеГде хранятся
Заказчик (customer)На своём шарде
Команды (teams)На шарде своего заказчика
Виртуальные ключиНа шарде своего заказчика
Бюджеты и rate limit'ыНа шарде своего владельца

Поэтому списание по цепочке «виртуальный ключ → команда → заказчик» остаётся одной атомарной записью на одном шарде.

Кластерная конфигурация с поддержкой фактора репликации меньше чем количество узлов будет поддержана в будущих релизах Meridian.

Страница Shards

Страница Cluster → Shards (/workspace/cluster/shards). Данные обновляются каждые 5 секунд, кнопка обновления рядом с Add запрашивает их сразу.

Страница Shards

Список шардов

Левая панель — таблица шардов.

КолонкаЗначение
IDИдентификатор шарда.
StateСостояние шарда. См. Статусы шардов.
CustomersЧисло заказчиков на шарде. Для orphaned — прочерк.

Щелчок по строке открывает шард в правой панели. Меню ⋯ в строке содержит действие Delete.

Карточка шарда

Правая панель — выбранный шард.

ПолеЗначение
IDИдентификатор шарда.
StateСостояние шарда.
Quorumyes (3/3 healthy voters) — кворум есть: живо 3 голосующих реплики из 3. no (…) — кворум потерян. unknown или — — данных о здоровье пока нет.
conf_verВерсия конфигурации шарда. Растёт, когда на шард или с него переносятся заказчики.
next_replica_idИдентификатор, который получит следующая реплика шарда.
created_at, updated_atВремя создания и последнего изменения.

Ниже на карточке:

  • Replicas — реплики шарда: Replica ID, Node, Role (voter или learner).
  • Ownership — сколько на шарде заказчиков (Customers), команд (Teams) и виртуальных ключей (Virtual keys).
  • Migrations — миграции, в которых участвует шард: направление (на шард или с шарда), заказчик, откуда и куда, фаза, возраст. Метка stuck отмечает зависшую миграцию.

Добавление шарда

Диалог Add a shard

Нажмите Add над списком шардов.

Введите Shard ID, например shard1. Допустимы латинские буквы, цифры, ., _ и -, первый символ — буква или цифра, длина до 64 символов. Имя _meta зарезервировано.

Нажмите Add shard.

Что происходит дальше:

  1. Кластер сохраняет новую версию топологии. Шард размещается на активных нодах, но не больше max_replicas из правила размещения.
  2. Лидер _meta в фоне создаёт Raft-группу на выбранных нодах.
  3. Когда версия становится Active, шард появляется в маршрутизации и готов принимать заказчиков.

Сразу после создания в поле Quorum может стоять —: группа ещё собирается. Через несколько секунд там появится число живых реплик.

Если шаг создания не удался, кластер откатывает объявление шарда новой версией топологии. Обе версии видны в журнале.

Типичные ошибки:

СообщениеПричинаЧто делать
Your license does not include multi-shard clustering…Лицензия без sharding.Обновите лицензию.
The cluster topology changed since this page loaded…Пока открыт диалог, версия топологии изменилась.Повторите через несколько секунд.
Шард уже существуетИдентификатор занят.Выберите другой ID.

Удаление шарда

⋯ → Delete в строке шарда. Удаление отклоняется, если:

  • это shard0;
  • на шарде есть заказчики — сначала перенесите их на другие шарды;
  • шард участвует в незавершённой миграции.

Удаление останавливает реплики на всех нодах и удаляет данные шарда. Вернуть удалённый шард можно только созданием нового и переносом заказчиков. Для удаления нужно право cluster.shard.delete.

Статусы шардов

Состояние шарда складывается из трёх независимых признаков.

Состояние в документе — колонка State

StateЗначениеЧто делать
activeШард объявлен в Active-версии топологии и обслуживается.Нормальное состояние.
orphanedШард остался в базе данных, но отсутствует в Active-версии топологии. Обычно это след незавершённого удаления или неудачного создания.Удалите шард через ⋯ → Delete — удаление дочищает оставшиеся данные.

В документе топологии есть значение stopped, но оно зарезервировано и не применяется. Остановить шард нельзя.

Здоровье группы — поле Quorum

Здоровье пересчитывается каждые 5 секунд по данным gossip о живых нодах. Кворум — voters / 2 + 1.

ЗдоровьеКак выглядитЗначениеЧто делать
healthyyes (3/3 healthy voters)Живы все голосующие реплики.Нормальное состояние.
degradedyes (2/3 healthy voters), метка degraded на странице StatusКворум есть, но часть реплик недоступна. Шард работает, запас отказоустойчивости снижен.Верните недоступную ноду. Если нода потеряна, выведите её через Drain и Exclude и добавьте замену — реплики пересоберутся на живых нодах.
quorum_lostno (1/3 healthy voters), метка quorum lostЖивых голосующих реплик меньше кворума. Шард не принимает записи: запросы заказчиков этого шарда отклоняются. Ноды перестают принимать трафик (Not serving).Срочно верните недоступные ноды. Авто-восстановление такой шард не трогает. Если ноды потеряны безвозвратно, используйте аварийные инструменты — см. Эксплуатация.
unknownunknown или —Здоровье ещё не вычислено: нода только стартовала или группа только создана.Подождите несколько секунд. Если состояние не меняется, проверьте, что gossip видит ноды на странице Status.

Локальная реплика на ноде

Нода может не запустить свою реплику шарда. Такое состояние видно в поле local_replica ответа GET /api/cluster/v1/shards/{shard_id} и в local_shards ответа GET /api/cluster/v1/status.

СостояниеЗначениеЧто делать
runningРеплика работает.Нормальное состояние.
parked_store_missingНа ноде нет каталога данных реплики. Возможно, volume подмонтирован не туда.Проверьте монтирование data_dir. Если данные действительно потеряны — выполните reseat.
parked_store_unreadableДанные реплики есть, но повреждены.Выполните reseat.
parked_identity_mismatchДанные принадлежат другой ноде, шарду или кластеру.Проверьте, что каталог подключён к правильной ноде. Затем выполните reseat.

Reseat выдаёт реплике новый идентификатор, и кворум заново реплицирует её данные:

curl -X POST http://localhost:8080/api/cluster/v1/groups/shard1/replicas/node2/reseat

Операция необратима: данные старой реплики отбрасываются.

Миграция заказчика между шардами

Миграция переносит заказчика на другой шард вместе с командами, виртуальными ключами, бюджетами и rate limit'ами.

Когда нужна:

  • Балансировка. Заказчик с высокой нагрузкой переезжает на свежий шард.
  • Изоляция. Важный заказчик получает отдельный шард.
  • Удаление шарда. Перед удалением все заказчики переносятся на другие шарды.

Запуск миграции

Миграция запускается со страницы заказчика, а не со страницы Shards.

Откройте Governance → Customers и выберите заказчика.

В блоке Danger Zone найдите строку Shard. Там указан текущий шард заказчика. Нажмите Migrate.

В поле Target shard выберите шард назначения. В списке нет текущего шарда и шардов в состоянии orphaned.

Отметьте флажок I understand that in-flight requests may fail with 5xx errors while the migration runs и нажмите Migrate.

Кнопка Migrate недоступна, если у заказчика уже идёт миграция, нет подходящего шарда назначения или нет права cluster.shard.migrate.

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

Отслеживание

Прогресс виден на странице Shards в блоке Migrations карточки шарда — исходного или шарда назначения. Строка показывает фазу и возраст миграции. Страница заказчика тоже показывает, что миграция идёт и в какой она фазе.

Пока миграция не завершена:

  • изменения заказчика, его команд и виртуальных ключей отклоняются с кодом 409 — повторите их после завершения; чтение работает;
  • исходный шард и шард назначения нельзя удалить;
  • для этого заказчика нельзя запустить вторую миграцию. Разные заказчики мигрируют параллельно.

Фазы миграции

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

ФазаЦветЧто происходит
plannedсерыйМиграция создана и ждёт запуска.
frozenсерыйНа исходном шарде запрещены изменения бюджетов переносимых групп.
snapshottedсерыйСостояние бюджетов сохранено в снимок.
appliedсерыйСнимок импортирован на шард назначения.
publishedсерыйНазначение заказчика переключено на новый шард. Точка невозврата.
committedзелёныйМиграция завершена. На исходном шарде установлено перенаправление для поздних запросов.
abortedкрасныйМиграция отменена. Заказчик остался на исходном шарде.
failedкрасныйМиграция не завершилась и остановлена автоматически. Заказчик остался на исходном шарде.

Метка stuck появляется, если миграция не завершилась за 30 минут.

Если миграция зависла или упала

Кластер сам повторяет незавершённые миграции: каждые 30 секунд он продолжает до 10 миграций, которые не продвигались дольше 30 секунд. Каждый шаг идемпотентен, повтор безопасен. Текст последней ошибки хранится в поле error_message миграции.

СитуацияЧто происходитЧто делать
Ошибка шага, миграция младше 30 минутФаза не меняется, кластер повторяет шаг.Подождите. Проверьте, что у обоих шардов есть кворум.
Старше 30 минут в planned, frozen или snapshottedМиграция автоматически отменяется и получает фазу failed.Устраните причину и запустите миграцию заново.
Старше 30 минут в applied или publishedАвтоматической отмены нет, миграция помечена stuck.Восстановите кворум шардов и повторите миграцию через API retry.

В интерфейсе нет кнопок отмены и повтора — используйте API:

# Повторить с текущей фазы
curl -X POST http://localhost:8080/api/cluster/v1/migrations/{migration_id}/retry

# Отменить (до snapshotted включительно)
curl -X POST http://localhost:8080/api/cluster/v1/migrations/{migration_id}/abort

# Аварийная отмена (до applied включительно)
curl -X POST "http://localhost:8080/api/cluster/v1/migrations/{migration_id}/abort?force=true"

После published отменить миграцию нельзя. Чтобы вернуть заказчика, запустите обратную миграцию. История завершённых миграций хранится 30 дней.

API

Создание и удаление шарда требуют заголовка If-Match с текущей Latest-версией топологии: без него — 428, с устаревшей версией — 412. Параметр dry_run=true возвращает план без изменений. Миграции недоступны без PostgreSQL: сервер отвечает 501.

Полная спецификация — в справочнике API.

Содержание