Хаосные реплицированные таблицы

Хаосные реплицированные динтаблицы в YTsaurus функционально похожи на реплицированные, но основанны на новом протоколе хаосной репликации. Как и обычные реплицированные, они позволяют иметь несколько копий одной и той же таблицы на разных кластерах, обновляемых в реальном времени, причём копии строго консистентны друг с другом и вместе представляют постоянно доступную динамическую таблицу с полной поддержкой транзакций.

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

  • На каждом кластере должна быть реплика специального вида - очередь репликации.
  • Репликация делается по pull-модели, при этом в качестве источника может быть использована любая доступная очередь, содержащая достаточно свежие данные.
  • Данные о состоянии реплик хранятся на отдельных кластерах хаосных метаданных в виде карточки репликации
  • Для совместимости с обычными реплицированными используется объект chaos_replicated_table, который, в отличие от replicated_table, не содержит никаих данных - это просто прокси-узел к хаосным метаданным и репликам.
  • Хаосные метаданные располагаются в специальном chaos cell bundle. chaos_replicated_table подвязывается к хаосному бандлу.

Хаосные реплицированные динтаблицы могут быть как сортированные, так и упорядоченные. Для упорядоченных динтаблиц каждая реплика используется и как реплика с данными и как очередь репликации для других реплик. Для сортированных динтаблиц реплики с даными и реплики с очередью репликации - принципиально разные, и имеют разные типы.

Создание хаосной реплицированной динтаблицы

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

  1. Создание хаосной динтаблицы. Сперва нужно создать объект вида chaos_replicated_table. Несмотря на то, что это просто прокси, это удобная точка входа, которая сильно упрощает работу с хаосными реплицированными таблицами. (К тому же, chaos_replicated_table для всех операций требует только read-доступа к кластеру, на котором располагается, и продолжет быть доступной во время обновления, если обновление проводится в режиме с доступом чтений.)

При создании нужно обязательно указать атрибут chaos_cell_bundle - к какому хаосному бандлу будет привязана таблица и в каком будут жить все необходимые метаданные. Также желательно указать атрибут schema - при его наличии можно будет указывать chaos_replicated_tableя прямо для селектов и лукапов.

yt create chaos_replicated_table //path/to/replicated_table --attr '{
  chaos_cell_bundle=...;
  schema=[...];
}'
  1. Создание реплики с данными. Это реплика, в которой хранятся сами данные в привычном формате (если отвязать реплику от репликации, это будет обычная динтаблица, со всеми данными). Для того чтобы таблица-реплика получилась привязанной к chaos_replicated_table, сперва нужно создать объект вида chaos_table_replica - часть метаданных, опиысывающих связь. Он полностью аналогичен table_replica для реплицированных динтаблиц. При создании chaos_table_replica важно указать к какой chaos_replicated_table она относится, а также какую таблицу-реплику описывает. Обратите внимание на "content_type" = "data" - это указывает на то, что реплика содержит данные и не может быть использована в качестве источника репликации. Если вы хотите создать реплику упорядоченной динтаблицы нужно указать "content_type" = "queue" - тогда реплика будет работать и как реплика с данными, и как источник для репликации.
$ yt create chaos_table_replica --attr '
{
     "table_path" = "//path/to/replicated_table";
     "cluster_name" = replica_cluster;
     "replica_path" = "//path/to/data";
     "content_type" = "data";
     "mode" = "sync";
     "enabled" = %true;
}'
1-2-3-4

Операция создания chaos_table_replica вернёт идентификатор свежесозданной реплики. Его нужно использвать в качестве upstream_replica_id для таблицы-реплики. upstream_replica_id можно как указать при создании таблицы, так и поменять с помощью alter_table.

$ yt --proxy replica_cluster create table //path/to/data --attr '{dynamic=%true; schema=[...]; upstream_replica_id="1-2-3-4"}'
# Или
$ yt --proxy replica_cluster alter-table --upstream-replica-id 1-2-3-4 //path/to/data
  1. Создать реплику с очередью репликации (только для сортированных хаосных динтаблиц). Этот шаг аналогичен созданию реплики с данными, но требует указать "content_type" = "queue" при создании chaos_table_replica, а также использовать тип replicated_log_table.

При создании очереди можно указать pivot_keys - тогда очередь будет разбитой на таблеты. Шардировать можно только один раз при создании. Если в будущем потребуется больше шардов, это можно сделать только создав новую очередь репликации, и удалив старую (хаос позволяет это сделать на живой таблице).

$ yt create chaos_table_replica --attr '
{
     "table_path" = "//path/to/replicated_table";
     "cluster_name" = replica_cluster;
     "replica_path" = "//path/to/replication_queue";
     "content_type" = "queue";
     "mode" = "sync";
     "enabled" = %true;
}'
5-6-7-8
$ yt --proxy zeno create replication_log_table //path/to/replication_queue --attr '{dynamic=%true; schema=[...]; upstream_replica_id="5-6-7-8"}'

Работа с хаосной реплицированной динтаблицей

Проще всего всегда использовать chaos_replicated_table - и для записи, и для чтения. Так будут сразу обеспечены все транзакционные гарантии.

Тем не менее, хаос поддерживает и доступ ко всей хаосной реплицированной таблице через любую реплику:

  • при записи как в chaos_replicated_table, так и в любую реплику, запись будет применяться сразу ко всей хаосной реплицированной таблице в соответствии с её текущим состоянием (например, при формальной записи в асинхронную реплику данные в этой транзакции будут на самом деле записаны только в синхронные реплики).
  • чтение из реплики читает данные только из неё самой (осторожно, в будущем это поведение может поменяться).
  • чтение из реплики, с указанием опции replica_consistency=sync будет читать из синхронной реплики (или достаточно свежей асинхронной, и не обязательно той, которая была указана в операции).
  • чтение из chaos_replicated_table делается всегда в режиме replica_consistency=sync, т.е. только из достаточно свежей реплики.

Добавление новой реплики

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

Чтобы добавить новую реплику и не требовать репликации данных за всё время существования, есть несколько способов:

  • Создать реплику с указанием catchup=%false. В таком случае будет считаться что история реплике не нужна и данные польются начиная с некоторого таймстемпа уже после создания. В случае реплики с данными в ней будут только новые записи, и такая реплика будет отличаться от других по данным. Но для добавления новой очереди репликации режим catchup=%false выглядит разумным вариантом по умолчанию, ведь обычно в очередях репликации хранится только малая часть свежих данных, ещё не доехавших до остальных реплик.
  • Указать при создании реплики replication_progress. Тогда репликация в реплику продолжится с указанного прогресса. Этот способ позволяет явно проконтролировать момент, с которого польются реплицированные данные. Подробнее о прогрессе репликации будет ниже.
  • Указать прогресс на таблице-реплике. Аналогично предыдущему, репликация продолжится начиная с указанного прогресса. Это наиболее предпочтительный способ, поскольку прогресс явно хранится вместе с таблицей в виде атрибута. Важно: прогресс на таблице должен быть больше или равен тому, который указан в chaos_table_replica. Если прогресс на таблице вдруг станет меньше, репликация остановится.

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

Копирование существующей реплики

Рассмотрим подробнее частый сценарий: копирование существующей реплики на новый кластер. Новая реплика должна быть полностью идеентична старой и в неё должна начаться репликация. Распишем последовательность шагов, которые нужно сделать:

  1. Отмонтировать реплику-донор (стоит предварительно перевести её в асинхронный режим). Это нужно для фиксации прогресса репликации.
  2. Прочитать прогресс из атрибута @replication_progress и запомнить его.
  3. Создать новую реплику командой create chaos_table_replica. Это позволит сохранить данные в очередях репликации до того момента, когда реплика начнет работать. Получившийся идентификатор нужно запомнить для последующей подстановки в upstream_replica_id
  4. Скопировать реплику-донор на новый кластер. Это потенциально долгий шаг, его можно оптимизировать: сперва скопировать реплику локально (командоый yt copy) - это быстро создаст необходимый снапшот данных, после чего копировать его в фоне и сразу переходить к следующему шагу
  5. Примонтировать реплику-донор. В неё пойдёт репликация, но данные в копии уже не поменяются.
  6. После окончания копирования установить на новой таблице правильный replication_progress и upstream_replica_id.
  7. Примонтировать новую реплику. Она должна обновить прогресс в карточке репликации на тот, который был ей выставлен, и запустить репликацию.

Необходимое число очередей репликации

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

Если предположить сценарий, в котоорм, пусть на короткое время, запись идёт только в одну синхронную очередь, то репликация сломается при внезапной недоступности этой очереди. Такая конфигурация может быть допустимой, только если очередь будет находиться на кросс-датацентровом кластере.

Хаос-целлы

Отказоустойчивость и постоянная доступность хаоса достигается благодаря отдельному слою хаосных метаданных, которые располагаются на хаос-целлах. Хаос-целлы располагаюся на кросс-дц кластерах, к томуже информация может быть смигрирована между хаос-целлами при необходимости даунтайма части хаос-целлов (напрмер, при обновлениях).

Как и таблет-целлы, хаос-целлы объединяются в бандлы (chaos cell bundle). Бандлы нужны для изоляции и учёта ресурсов между разными потребителями. В отличие от tablet cell bundle, целлы хаосного бандла известны сразу всем кластерам. Можно прямо в UI посмотреть список всех хаос-целлов, в том числе и тех, которые физически располагаются на других кластерах.

Для того, чтобы воспользоваться хаосной репликацией, у вас должен быть chaos cell bundle, которым разрешено пользоваться.

Прогресс репликации

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

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

Прогресс репликации представляет собой ступенчатый график в пространстве ключей и времени: для каждого диапазона ключей указывается timestamp, до которого этот диапазон дореплицировался (включительно). Это позволяет делать запросы на чтение данных отдельно по диапазонам, причём диапазоны не обязательно должны совпадать с ключами шардирования очередей репликации.

Прогресс представляется в виде последовательности сегментов (lower key, timestamp). Последний ключ задаётся отдельным полем upper_key. Прогресс на таблице можно посмотреть через атрибут @replication_progress - рекомендуется это делать только на отмонтированных таблицах, потому что на примонтированных реальный прогресс может оказаться сильно больше. Поменять прогресс можно с помощью команды alter-table. Последнее может быть полезно, если требуется подключить новую реплику с подготовленными данными к существующей таблице.

Важно понимать, что у примонтированной реплики достоверный прогресс знает только таблетная нода для тех таблетов, которые на ней. Ни на мастере, который отвечает на чтение атрибута @replication_progress, ни на хаос-целле, с которого можно достать карточку репликации (о ней - ниже) информация о прогресее недостоверна, и by design, отстающая.

Карточка репликации

Карточка репликации - основные метаданыне для протокола хаосной репликации. В обычных пользовательских сценариях она не используется в явном виде, но может быть полезным при расследовании проблем.

В карточке содержится информация о репликах: какие кластера и таблицы, какие режимы реплик, а также, возможно, отставший, прогресс.

В карточке репликации есть дополнительно поля history и era. Эра - счётчик эпох хаосной репликации. Каждое изменение совокупного состояния реплик - добавление или удаление, а также смена режима - приводит к переходу на новую эру, В поле history указаны эпохи, в которых менялось состояние этой конкретной реплики. Поле history периодически подчищается в фоне.

Для того чтобы узнать уникальный идентификатор карточки, нужно прочитать атрибут @replication_card_id у реплицированной динтаблицы или у реплики. Чтобы получить саму карточку, достаточно сделать get по идентификатору (не забудтье добавить #).

Переключение режимов реплик

Переключение режимов реплик делается командой alter-table-replica, точно также как и для обычных упорядоченных. Можно как выключить-включить реплику (с помощью флагов enable/disable), так и поменять режим с синхронного на асинхронный и обратно - с помощью опции mode.

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

Автоматическое переключение режимов реплик

Как и обычные реплицированные, хаосные реплицированные таблицы поддерживают автоматическое переключение реплик.

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

При создании chaos_replicated_table можно указать атрибут replicated_table_options, в который передать ReplicatedTableOptions. Подробное описание ReplicatedTableOptions см в соответствующем разделе.

Если хаосная реплицированная динтаблица уже создана, то поменять опции можно с помощью команды alter_replication_card (ей нужно передать идентификатор карточки репликации, который указан в атрибуте @replication_card_id хаосной реплицированной таблицы и реплик):

yt.alter_replication_card(replication_card_id, replicated_table_options=replicated_table_options)
yt.alter_replication_card(replication_card_id, enable_replicated_table_tracker=True)

Для того, чтобы управлять автоматическим переключением отдельных реплик, на каждой реплике есть флаг enable_replicated_table_tracker, который можно либо указать при создании реплики, либо поменять для уже существующей реплики с помощью команды alter-table-replica:

$ yt alter-table-replica [--enable-replicated-table-tracker | --disable-replicated-table-tracker] replica_id

Атрибуты

Атрибуты chaos_table_replica

Имя Тип Значение
table_path string путь к chaos_replicated_table
replication_card_id TReplicationCardId явное указание карточки репликации (можно не указывать, если указан table_path)
cluster_name string крастер с таблице-репликой
replica_path string путь до таблицы-реплики
content_type ETableReplicaContentType data или queue в зависимости от того это данные или очередь репликации. Для реплик упорядоченных динтаблиц нужно указывать queue
mode ETableReplicaMode sync или async - режим реплики при создании
enabled bool true или false - должна ли реплика быть включена
catchup bool true если реплика должна подтянуть данные, false если нужно начать с чистого листа
replication_progress TReplicationProgress Прогресс при создании реплики (можно опустить, если прогресс уже есть на таблице-реплике)
enable_replicated_table_tracker bool true если для реплики должно быть включено автоматическое переключение режима