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

Общие сведения

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

Копии (реплики) реплицированной таблицы могут находиться как на том же кластере что и таблица источник (внутрикластерная репликация), так и на других кластерах, часто расположенных в разных ДЦ (межкластерная репликация). Репликация между динамическими таблицами позволяет иметь несколько копий одной и той же таблицы в независимых кластерах и организовать автоматическое копирование данных между ними.

Использование реплицированных динамических таблиц позволяет:

  • переживать сбои уровня ДЦ как на чтение, так и на запись;
  • повысить отказоустойчивость пользовательского сервиса за счёт изоляции реплик таблицы;
  • проводить обновления кластеров YTsaurus с меньшим временем простоя для пользователя (или без такового).

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

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

Для того чтобы воспользоваться репликацией, необходимо иметь один мета-кластер и один или более кластеров-реплик. Настройка репликации состоит из нескольких шагов:

  1. Создание на мета-кластере специального объекта replicated_table, хранящего информацию о репликах и статусе репликации;
  2. Создание на каждом из кластеров-реплик по одной динамической таблице (сортированной или упорядоченной в зависимости от решаемой задачи);
  3. Настройка реплик на мета-кластере и включение репликации.

После выполнения указанных шагов можно записывать или удалять данные из реплицированной таблицы на мета-кластере с помощью команд insert-rows и delete-rows . Внесённые изменения попадут на кластеры-реплики.

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

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

Запись данных

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

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

Примечание

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

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

Для того чтобы разрешить клиенту запись в реплицированную динамическую таблицу, у которой нет ни одной синхронной реплики, у команд записи (insert-rows, delete-rows) имеется специальный флаг require_sync_replica (значение по умолчанию true). Выставление флага в false разрешает запись в реплицированную динамическую таблицу без синхронной реплики.

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

Чтение данных

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

Внимание

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

Внимание

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

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

Репликация

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

Гарантии

Для асинхронных реплик транзакции репликации (доставляющие данные до реплик) никак не скоординированы с транзакциями записи в реплицированную таблицу. Изменения в одной транзакции записи в реплицированную таблицу могут быть разбиты на несколько транзакций репликации. Гарантии:

  • для читателя реплики нет гарантий атомарности — он может застать реплику в промежуточном состоянии, когда к ней применилась лишь часть изменений транзакции;
  • гарантируется exactly-once семантика (каждая запись в реплицированную таблицу будет доставлена до всех реплик ровно один раз);
  • гарантируется правильный порядок доставки изменений в таблицы-реплики — все транзакции в таблете реплицированной таблицы упорядочиваются относительно времени коммита (commit timestamp). Именно в таком порядке изменения отправляются в реплики.

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

К таблицам-репликами можно общаться напрямую через кластеры, где эти реплики физически находятся. Таблицы-реплики являются особенными. При репликации в таблицах-репликах оказываются данные с timestamp-ом, сгенерированном на мета-кластере. Записывать данные в таблицы-реплики напрямую (минуя мета-кластер) нельзя, система прилагает максимум усилий для того, чтобы запретить такую запись (выставив upstream_replica_id в нулевое значение, подобную запись можно осуществить. Риски такого действия описаны далее). Чтение данных из таблиц-реплик возможно. Такой способ использования приветствуется в случае, когда таблицы-реплики обслуживают размещенный в том же ДЦ realtime-сервис, отдающий данные внешнему пользователю.

Ограничения по консистентности данных, которые можно прочитать:

  • если реплика синхронна, то чтение без указания timestamp даст самое свежее состояние (на уровне отдельных значений отдельных строк, в частности, snapshot-изоляция отсутствует: разные строки, а также разные колонки одной и той же строки могут отвечать различным моментам времени; гарантируется, видимость данных из всех закоммиченных транзакций);
  • чтения из реплики с указанием timestamp возможно, но сам timestamp при этом рекомендуется получить на мета-кластере, т.к. этот timestamp на самом деле является невалидным для кластера с репликой (так как пришел из мета-кластера);
  • для асинхронных реплик всегда возможно (и есть) отставание, так что любое чтение будет возвращать отстающие данные; при репликации не гарантируется консистентность (транзакция в реплицированной таблице могла атомарно изменить ключи A и B, из реплики можно прочитать новое значение для A, а после этого — старое для B).

Реплики

С каждой реплицированной таблицей связан набор реплик (объектов типа table_replica) создаваемых следующим образом:

Создание реплики:

yt create replicated_table //tmp/replicated --attr '{dynamic=%true; schema=[{name=k;type=string;sort_order=ascending};{name=v;type=string}]}'

yt create table_replica --attr '{table_path="//tmp/replicated"; cluster_name="replica_cluster";replica_path="//tmp/replica"}'

Данный набор команд создает на метакластере реплицированную таблицу //tmp/replicated, а также конфигурирует для нее (асинхронную) реплику на кластере replica_cluster по пути //tmp/replica.

Указанные команды не создают сами по себе таблицу //tmp/replica на кластере-реплике, а лишь настраивают реплику для //tmp/replicated. Создание таблиц-реплик необходимо выполнять самостоятельно.

Стоит обратить внимание, что сразу после создания реплики, она находится в отключенном состоянии (state = "disabled"), при котором репликация отключена. Чтобы запустить реплику, необходимо выполнить команду alter-table-replica --enable. Подробнее ниже.

У каждой созданной реплики (как и у любого объекта мастер-сервера) существует id. Для просмотра информации о реплике можно использовать следующие команды:

Просмотр реплики:

yt get //tmp/replicated/@replicas
yt get '#replica-id/@'

Удалить реплику можно как и иные объекты с помощью команды remove:

Удаление реплики:

yt remove '#replica-id'

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

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

Если же хочется добавить новую реплику или уже имеется таблица-реплика, которая хранит требуемое состояние данных, то необходимо при создании объекта table_replica указать один из двух атрибутов: start_replication_timestamp или start_replication_row_indexes. В случае указания start_replication_timestamp реплицироваться будут все изменения, у которых commit ts строго больше указанного значения (имеется ввиду timestamp в смысле метакластера). Если нужно начать репликацию просто с некоторого момента, то самое удобное — это указать timestamp, полученный с помощью вызова generate-timestamp к метакластеру. В случае start_replication_row_indexes необходимо для каждого таблета реплицированной таблицы указать, с какого row index в этом таблете следует реплицировать данные в реплику. Актуальные row indexes можно получить из запроса get-tablet-infos.

Создание таблиц-реплик

Таблица-реплика — это обычная (динамическая) таблица на целевом кластере. Но при ее создании необходимо задать атрибут upstream_replica_id, в котором указать id объекта-реплики на метакластере. Указание upstream_replica_id разрешает репликатору выполнять запись из метакластера в кластер с репликой, а также запрещает прямую (минуя репликатор) запись в таблицу-реплику. Указание данного id защищает от ошибок конфигурации, при которых одна и та же таблица оказывается репликой для нескольких реплицированных таблиц.

Создание таблицы-реплики:

yt create table //tmp/replica --attr '{dynamic=%true; upstream_replica_id=replica-id;schema=[{name=k;type=string;sort_order=ascending};{name=v;type=string}]}'

Атрибут upstream_replica_id у таблицы можно изменить и после создания с помощью команды alter-table. При этом, все таблеты таблицы должны быть отмонтированы.

Настройки реплик

Сразу после создания реплики она находится в состоянии disabled (атрибут state). В таком положении репликация не осуществляется. Для того, чтобы включить реплику, необходимо воспользоваться командой alter-table-replica:

Включение реплики:

yt alter-table-replica replica-id --enable

Реплика перейдет в состояние enabling, а затем, когда будет включена успешно — в состояние enabled.

Реплику можно отключить, прервав тем самым репликацию. Для отключения реплики следует использовать ту же команду alter-table-replica. Отключение также асинхронно, реплика перейдет в состояние disabling, а затем disabled:

Выключение реплики:

yt alter-table-replica replica-id --disable

Ручная синхронизация

В ряде случаев для работы достаточно иметь лишь асинхронные реплики (они дают максимальную возможную скорость записи в реплицированную таблицу, т. к. все действия производятся в фоне), но при этом иметь возможность явно дождаться окончания репликации в какую-либо реплику. Для этого существует команда get-in-sync-replicas. Для ее работы нужно указать timestamp и система найдет все реплики, до которых гарантированно доехали все изменения с timestamp не выше заданного. К примеру, можно сгенерировать текущий timestamp, а затем в цикле ожидать того момента, когда заданная реплика окажется в списке, возвращаемом командой. После этого в данную реплику можно пойти с запросом и передать timestamp. Это будет гарантировать консистентность чтения.

Режимы репликации

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

Существует возможность асинхронной репликации без сохранения исходных timestamp. Чтобы воспользоваться этим режимом необходимо создать реплику с атрибутами {"mode": "async", "preserve_timestamps": "false"}, при этом таблицу-реплику следует создавать без указания атрибута upstream_replica_id. Данная возможность может быть полезна в ряде случаев:

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

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

Если кластер, на котором находится синхронная реплика, недоступен, то запись в реплицированную динамическую таблицу останавливается. Чтобы продолжить запись необходимо переключить синхронную реплику на другой кластер. В системе YTsaurus реализована возможность автоматического переключения синхронной реплики. Чтобы активировать данную возможность, следует либо создать реплицированную динамическую таблицу с атрибутом replicated_table_options={enable_replicated_table_tracker=%true}, либо добавить указанный атрибут впоследствии с помощью вызова yt set. В таком случае система YTsaurus будет следить за репликами таблицы и при необходимости переключать синхронную реплику на другой кластер.

Для настройки числа синхронных реплик существуют две настройки - min_sync_replica_count и max_sync_replica_count. Автоматика при наличии доступных реплик переключает их в синхронный режим, но чтобы было не более max_sync_replica_count синхронных реплик. Также автоматика следит за тем, чтобы число синхронных реплик не опускалось ниже min_sync_replica_count.
Если не указаны min_sync_replica_count и max_sync_replica_count, то оба поля будут по умолчанию равны 1. Если не указано только min_sync_replica_count, то оно будет равно max_sync_replica_count. Если же не указано только max_sync_replica_count, то оно будет равно общему числу реплик. Таким образом, по умолчанию автоматика поддерживает ровно одну синхронную реплику.

Существует режим, когда система YTsaurus перестаёт следить за какой-либо репликой таблицы, но продолжает следить за остальными репликами. Для включения такого режима для реплики (table_replica) с помощью вызова yt set необходимо выставить атрибут enable_replicated_table_tracker=%false.

Текущий режим для таблицы-реплики можно посмотреть с помощью аттрибута replicated_table_tracker_enabled объекта реплики мета-кластера:

$ yt --proxy meta-cluster get //home/some_meta_table/@replicas

"table-replica-id" = {
     "cluster_name" = "some_name";
     "replica_path" = "//home/some_table";
     "state" = "enabled";
     "mode" = "async";
     "replicated_table_tracker_enabled" = %false;
 };

Одновременное переключение синхронных реплик группы таблиц

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

Работа с коллокациями реплицированных таблиц:

# Создать коллокацию с указанием списка таблиц.
yt create table_collocation --attributes '{collocation_type=replication; table_paths=["//tmp/replicated_table_1"; "//tmp/replicated_table_2"]}'

# Узнать список таблиц в коллокации.
yt get "#collocation-id/@table_ids"
yt get "#collocation-id/@table_paths"

# Узнать id коллокации, которой принадлежит данная таблица.
yt get //tmp/replicated_table_1/@replication_collocation_id

# Узнать список всех таблиц в коллокации, которой принадлежит данная таблица.
yt get //tmp/replicated_table_1/@replication_collocation_table_paths

# Добавить таблицу в коллокацию.
yt set //tmp/replicated_table_3/@replication_collocation_id collocation-id

# Удалить таблицу из коллокации.
yt remove //tmp/replicated_table_3/@replication_collocation_id

Указание предпочтительных кластеров для синхронных реплик

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

yt set //tmp/replicated_table/@replicated_table_options/preferred_sync_replica_clusters '["cluster-name"]'

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

Ограничение скорости репликации

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

Относительный троттлер репликации

Настраивается через атрибут mount_config/relative_replication_throttler. Это словарь, который может содержать следующие значения.

Имя Тип Описание Значение по умолчанию
enable bool Включён ли троттлер %false (может зависеть от кластера)
ratio double Отношение скорости репликации к скорости записи 2

Относительный троттлер ограничивает скорость асинхронной репликации по отношению к скорости записи. К примеру, если некоторый набор данных был записан в течение одного часа и в это время асинхронная реплика была недоступна, то при ratio = 3 после возвращения реплики эти данные будут отреплицированы за 20 минут.

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

Пример настройки:

yt set //tmp/replicated_table/@mount_config/relative_replication_throttler '{ratio=1.5}'

Абсолютный троттлер репликации

Настраивается через атрибут таблицы mount_config/replication_throttler, у которого можно задать два значения:

  • limit — предел для среднего значения пропускной способности в байт/с;
  • period — временной интервал в мс, в течении которого замеряется среднее значение пропускной способности.

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

yt set //tmp/replicated_table/@mount_config/replication_throttler '{period=1000;limit=1000000}'

Примечание

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

Сохранение индекса таблета при репликации упорядоченной таблицы

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

Изменение схемы

Совместимое изменение схемы как таблицы-реплики, так и реплицированной таблицы можно выполнить с помощью команды alter-table. Команду необходимо выполнять на каждой таблице независимо. Перед вызовом команды таблицу необходимо отмонтировать.

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

Устойчивость к даунтаймам и обновлениям

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

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

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

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

Атрибуты

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

Имя Тип Описание
replicas Guid->ReplicaInfo Описание реплик (ключи — id реплик, значения — некоторые их важные атрибуты)
replicated_table_options ReplicatedTableOptions Настройки автоматики переключения реплик
preserve_tablet_index bool Сохранять при репликации упорядоченных динтаблиц tablet index; по умолчанию %false

Здесь ReplicatedTableOptions имеют вид:

Имя Тип Описание
enable_replicated_table_tracker bool Включена ли автоматика переключения синхронных реплик; по умолчанию %false
max_sync_replica_count integer Максимальное и желаемое количество синхронных реплик, которые нужно поддерживать автоматике
min_sync_replica_count integer Минимальное количество синхронных реплик, которые нужно поддерживать автоматике
preferred_sync_replica_clusters list Список предпочтительных кластеров для синхронных реплик

Каждая реплика описывается словарём ReplicaInfo следующего вида:

Имя Тип Описание
cluster_name string Имя кластера-реплики
replica_path string Путь к таблице с репликой на кластере-реплике
state TableReplicaState Состояние реплики
mode TableReplicaMode Режим работы реплики: async или sync
replication_lag_time Duration Оценка лага реплики
errors Error* Список ошибок при репликации на данную реплику
preserve_timestamps bool Сохранять исходные timestamp ? По умолчанию true. Имеет смысл только для асинхронных реплик
atomicity EAtomicity full или none. Имеет смысл только для асинхронных реплик

Параметр replication_lag_time дает примерную оценку лага репликации (с точностью до десятков секунд).

Сам объект-реплика помимо перечисленных атрибутов (а также атрибутов, присущих всем объектам) обладает также рядом дополнительных (все их можно узнать, выполнив запрос вида yt get '#replica-id/@'):

Имя Тип Описание
mode ReplicaMode Режим реплики: sync, async
start_replication_timestamp Timestamp Начальный timestamp для реплики
table_path string Путь к реплицированной таблице на метакластере
tablets TabletReplicaInfo* Описание состояния таблетов; позиция в списке соответствует индексу таблета, как в самой таблице
enable_replicated_table_tracker bool Включает автоматику переключения синхронных реплик (см. выше); по умолчанию %true

Структура TabletReplicaInfo имеет следующий вид:

Имя Тип Описание
tablet_id Guid Id таблета
state TableReplicaState Состояние данной реплики данного таблета
current_replication_row_index integer Граница репликации в очереди по индексу записи (репликации подлежат записи с индексом >= данного)
current_replication_timestamp Timestamp Граница репликации в очереди по timestamp (репликации подлежат записи с timestamp > данного)
replication_lag_time Duration Оценка лага реплики для данного таблета
flushed_row_count integer Количество записанных на диск строк в данном таблете; если реплицированная таблица заморожена, то это значение можно сравнивать с current_replication_row_index для слежения за репликацией
trimmed_row_count` integer Количество начальных строк в данном таблете, которые были реплицированы всюду и чанки которых были удалены (log truncation)
replication_error Error Описывает ошибку при репликации. В случае отсутствия ошибки данный тег также будет отсутствовать

В процессе работы репликатора параметры current_replication_row_index и current_replication_timestamp монотонно растут, отмечая успешно отреплицированные записи.

Проверка очереди репликации

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

  1. Выполнить команду freeze-table для реплицированной таблицы.
  2. Дождаться (опрашивая атрибут tablet_state у таблице), пока все таблеты перейдут в состояние frozen.
  3. Получить информацию о состоянии таблетов интересующей таблицы, для чего сделать запрос get #replica-id/@tablets. Каждый элемент списка-ответа описывает состояние репликации для заданного таблета реплицированной таблицы в заданную ее реплику. Для каждого таблета необходимо изучить значения flushed_row_count и current_replication_row_index и дождаться, пока они не станут одинаковы.

Примеры использования

Создание, настройка реплик

Примеры работают начиная с версии ytsaurus-client >= 0.8.19. .

Примеры использования реплицированных таблиц:

export YT_PROXY=cluster-name

# Создание реплицированной таблицы.
yt create replicated_table //tmp/replicated --attr '{
  dynamic=%true;
  schema=[{name=k;type=int64;sort_order=ascending};{name=v;type=int64}]
}'
730e-68d3e-3ff01a9-325bbdcd

# Создание реплики, связанной с кластером first-replica-cluster.
yt create table_replica --attr '{
  table_path="//tmp/replicated";
  cluster_name="first-replica-cluster";
  replica_path="//tmp/replica"
}'
730e-7bcd8-3ff02c5-fd0b36ee

# Создание второй реплики на кластере second-replica-cluster.
yt create table_replica --attr '{
  table_path="//tmp/replicated";
  cluster_name="second-replica-cluster";
  replica_path="//tmp/replica"
}'
730e-8611b-3ff02c5-f647333f

# Создание таблицы-реплики на кластере first-replica-cluster.
YT_PROXY=first-replica-cluster yt create table //tmp/replica --attr '{
  dynamic=%true;
  upstream_replica_id="730e-7bcd8-3ff02c5-fd0b36ee";
  schema=[{name=k;type=int64;sort_order=ascending};{name=v;type=int64}]
}'
6cd9-66770-3ee0191-980d9f6

# Создание таблицы-реплики на кластере second-replica-cluster.
YT_PROXY=second-replica-cluster yt create table //tmp/replica --attr '{
  dynamic=%true;
  upstream_replica_id="730e-8611b-3ff02c5-f647333f";
  schema=[{name=k;type=int64;sort_order=ascending};{name=v;type=int64}]
}'
78b6-1dacd9-3f40191-2057d1df

# Монтирование таблицы-реплики и реплицированной таблицы.
yt mount-table //tmp/replicated
YT_PROXY=first-replica-cluster yt mount-table //tmp/replica
YT_PROXY=second-replica-cluster yt mount-table //tmp/replica

# Запись данных в реплицированную таблицу.
echo '{k=1;v=100}' | yt insert-rows //tmp/replicated --format yson
Table //tmp/replicated has no synchronous replicas

# Выставление флага no-require-sync-replica, чтобы форсировать запись.
echo '{k=1;v=100}' | yt insert-rows //tmp/replicated --format yson --no-require-sync-replica

# Запись прошла успешно, но в реплике нет данных.
YT_PROXY=first-replica-cluster yt select-rows '* from [//tmp/replica]' --format yson

# Просмотр состояния реплики.
yt get '#730e-7bcd8-3ff02c5-fd0b36ee/@state'
"disabled"

# Реплика не была включена. Включение реплики.
yt alter-table-replica 730e-8611b-3ff02c5-f647333f --enable
yt alter-table-replica 730e-7bcd8-3ff02c5-fd0b36ee --enable

# Проверка успешности репликации.
YT_PROXY=first-replica-cluster yt select-rows '* from [//tmp/replica]' --format json
{"k":1,"v":100}

# Попытка прочитать данные прямо из реплицированной таблицы.
yt select-rows '* from [//tmp/replicated]' --format json
No in-sync replicas found for table //tmp/replicated

# Без синхронных реплик чтение выполнить не получится.
# Отключение второй реплики и повторная запись.
yt alter-table-replica 730e-8611b-3ff02c5-f647333f --disable
echo '{k=2;v=200}' | yt insert-rows //tmp/replicated --format yson --no-require-sync-replica

# Чтение из реплик
YT_PROXY=first-replica-cluster yt select-rows '* from [//tmp/replica]' --format json
{"k":1,"v":100}
{"k":2,"v":200}

YT_PROXY=second-replica-cluster yt select-rows '* from [//tmp/replica]' --format json
{"k":1,"v":100}

# Видно, что в first-replica-cluster данные пришли, а в second-replica-cluster нет.
# Неработающую репликацию можно заметить по растущему лагу.
yt get '#730e-8611b-3ff02c5-f647333f/@replication_lag_time'
141000

# Изменение типа репликации на first-replica-cluster и включение реплики.
yt alter-table-replica 730e-8611b-3ff02c5-f647333f --enable --mode sync

# Чтение данных из first-replica-cluster и проверка наличия данных.
YT_PROXY=first-replica-cluster yt select-rows '* from [//tmp/replica]' --format json
{"k":1,"v":100}
{"k":2,"v":200}

# Наличие синхронной реплики даёт возможность читать прямо из реплицированной таблицы.
yt select-rows '* from [//tmp/replicated]' --format json
{"k":1,"v":100}
{"k":2,"v":200}

# Удаление первой строки, на этот раз в синхронном режиме.
echo '{k=1}' | yt delete-rows //tmp/replicated --format yson

# Проверка выполнения команды.
YT_PROXY=first-replica-cluster yt select-rows '* from [//tmp/replica]' --format json
{"k":2,"v":200}

YT_PROXY=second-replica-cluster yt select-rows '* from [//tmp/replica]' --format json
{"k":2,"v":200}

# Отключение записи в реплицированную таблицу.
yt freeze-table //tmp/replicated

# Проверка того, что таблет заморожен, т. е. все данные записаны на диск.
yt get //tmp/replicated/@tablet_state
"frozen"

# Проверка, что в каждой из реплик все строки успешно отреплицированы.
# Для этого необходимо изучать атрибуты flushed_row_count и replicated_row_index.
yt get '#730e-7bcd8-3ff02c5-fd0b36ee/@tablets'
[
    {
        "flushed_row_count" = 5;
        "tablet_id" = "730e-68d3e-3ff02be-ee882e4a";
        "trimmed_row_count" = 2;
        "replication_lag_time" = 0;
        "current_replication_timestamp" = 1610012496066773010u;
        "current_replication_row_index" = 5;
        "state" = "enabled";
    };
]

yt get '#730e-8611b-3ff02c5-f647333f/@tablets'
[
    {
        "flushed_row_count" = 5;
        "tablet_id" = "730e-68d3e-3ff02be-ee882e4a";
        "trimmed_row_count" = 2;
        "replication_lag_time" = 0;
        "current_replication_timestamp" = 1610012496066773010u;
        "current_replication_row_index" = 5;
        "state" = "enabled";
    };
]

# Видно, что значения flushed_row_count и current_replication_row_index одинаковы, т. е. обе реплики полностью отреплицированы.
Предыдущая
Следующая