- Хаосные реплицированные таблицы
- Создание хаосной реплицированной динтаблицы
- Работа с хаосной реплицированной динтаблицей
- Добавление новой реплики
- Необходимое число очередей репликации
- Хаос-целлы
- Прогресс репликации
- Карточка репликации
- Переключение режимов реплик
- Автоматическое переключение режимов реплик
- Атрибуты
Хаосные реплицированные таблицы
Хаосные реплицированные динтаблицы в YTsaurus функционально похожи на реплицированные, но основанны на новом протоколе хаосной репликации. Как и обычные реплицированные, они позволяют иметь несколько копий одной и той же таблицы на разных кластерах, обновляемых в реальном времени, причём копии строго консистентны друг с другом и вместе представляют постоянно доступную динамическую таблицу с полной поддержкой транзакций.
По сравнению с обычными реплицированными, хаосные динтаблицы всё время доступны и на чтение, и на запись - это достигается благодаря протоколу хаосной репликации. Основные отличия хаосной репликации такие:
- На каждом кластере должна быть реплика специального вида - очередь репликации.
- Репликация делается по pull-модели, при этом в качестве источника может быть использована любая доступная очередь, содержащая достаточно свежие данные.
- Данные о состоянии реплик хранятся на отдельных кластерах хаосных метаданных в виде карточки репликации
- Для совместимости с обычными реплицированными используется объект
chaos_replicated_table, который, в отличие отreplicated_table, не содержит никаких данных - это просто прокси-узел к хаосным метаданным и репликам. - Хаосные метаданные располагаются в специальном chaos cell bundle.
chaos_replicated_tableподвязывается к хаосному бандлу.
Хаосные реплицированные динтаблицы могут быть как сортированные, так и упорядоченные. Для упорядоченных динтаблиц каждая реплика используется и как реплика с данными и как очередь репликации для других реплик. Для сортированных динтаблиц реплики с даными и реплики с очередью репликации - принципиально разные, и имеют разные типы.
Создание хаосной реплицированной динтаблицы
В этой секции описывается последовательность шагов, как быстро создать хаосную реплицированную динтаблицу, и какие основные интерфейсные отличия от реплицированной. Для более глубокого понимания того, как работают хаосные динтаблицы, стоит прочитать следующие секции.
- Создание хаосной динтаблицы. Сперва нужно создать объект вида
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=[...];
}'
- Создание реплики с данными. Это реплика, в которой хранятся сами данные в привычном формате (если отвязать реплику от репликации, это будет обычная динтаблица, со всеми данными). Для того чтобы таблица-реплика получилась привязанной к
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
- Создать реплику с очередью репликации (только для сортированных хаосных динтаблиц). Этот шаг аналогичен созданию реплики с данными, но требует указать
"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. Если прогресс на таблице вдруг станет меньше, репликация остановится.
При добавлении новой реплики с явно указанным прогрессом нужно быть уверенным, что текущие очереди репликации содержат необходимые данные. Обычно такого можно достичь с помощью отмонтирования уже существующей реплики с данными - тогда невозможность реплицировать в неё будет заставлять данные накапливаться в очередях.
Копирование существующей реплики
Рассмотрим подробнее частый сценарий: копирование существующей реплики с данными на новый кластер. Новая реплика должна быть полностью идеентична старой и в неё должна начаться репликация. Распишем последовательность шагов, которые нужно сделать:
- Отмонтировать реплику-донор (стоит предварительно перевести её в асинхронный режим), дождаться когда статус станет
unmounted. Это нужно для фиксации прогресса репликации. - Прочитать прогресс из атрибута
@replication_progressтаблицы реплики-донора и запомнить его. - Создать новую реплику командой
create chaos_table_replica, указав прогресс из предыдущего шага. Это позволит сохранить данные в очередях репликации до того момента, когда реплика начнет работать. Получившийся идентификатор нужно запомнить для последующей подстановки вupstream_replica_id. - Скопировать реплику-донор на новый кластер. Это потенциально долгий шаг, его можно оптимизировать: сперва скопировать реплику локально (командой
yt copy) - это быстро создаст необходимый снапшот данных, после чего копировать его в фоне и сразу переходить к следующему шагу. При копировании на другой кластер нужно делать remote copy для динтаблицы - так сохранится информация о всех таймстампах (если при копировании преобразовать таблицу в статическую, то информация о таймстампах потеряется, что может привести к потере данных после включения репликации). - Примонтировать реплику-донор. В неё пойдёт репликация, но данные в копии уже не поменяются.
- После окончания копирования установить на новой таблице правильный
replication_progressиupstream_replica_id(Несмотря на то, что вновь созданная реплика с пустым прогрессом подтянет прогресс из карточки, на этом шаге стоит всегда явно устанавливать прогресс на таблице-реплике - так можно быть уверенными, что он будет именно тот, какой ожидается). - Примонтировать новую реплику. Она должна обновить прогресс в карточке репликации на тот, который был ей выставлен, и запустить репликацию.
Так можно скопировать реплику с данными для сортированной хаосной динтаблицы. Реплику-очередь скопировать нельзя, но можно просто создать новую, указав catchup=%false - репликация последующих записей будет использовать в том числе и новую реплику-очередь.
Перемещение реплик
Можно перемещать реплики на новое место с одновременным обновлением пути в карточке репликации. Так как эта операция не атомарная, то, во избежание даунтаймов, рекомендуется предварительно переключить перемещаемую реплику в async-режим.
yt unmount-table <старый путь>yt move <старый путь> <новый путь>yt alter-table-replica --params '{replica_path="<новый путь>"}' <replica_id>yt mount-table <новый путь>
Перешардирование реплик-очередей
Реплики-очереди являются очередями, и поэтому нельзя напрямую изменить количество таблетов в таких репликах. Перешардирование реплик-очередей возможно только через пересоздание. Сделать это можно следующим способом:
- Завести новые реплики-очереди с желаемым количеством шардов в sync-режиме и указав
catchup=%falseиreplicated_table_tracker_enabled=%falseс новым путем. Последнее нужно, чтобы все новые реплики не стали async. - Убедиться, что в них началась запись: лаг реплики в интерфейсе должен оставаться околонулевым, а атрибут replication_lag_time должен расти
- Сгенерировать таймстемп
yt --proxy markov generate-timestampи запомнить его - Дождаться, когда значение replication_lag_timestamp всех реплик будет больше, чем timestamp, сгенерированный на предыдущем шаге. Посмотреть replication_lag_timestamp реплик таблицы можно командой
$ yt get "<путь к chaos_replicated_table>/@replicas" | grep replication_lag_timestamp
- Удалить старые реплики-очереди
- Если нужно, переместить новые реплики на место старых реплик
- Если нужно, включить автоматику переключение реплик через
alter-table-replica
Создание новой реплики для упорядоченной динтаблицы
Реплики упорядоченной динтаблицы представляют собой очереди и самый простой способ - создать новую реплику, указав catchup=%false - создаст реплику с работающей репликацией. Однако, в такой реплике номера строк будут отличаться от номеров строк в других репликах, что может привести к неожиданностям при чтении, особенно если $row_index указывается явно.
Чтобы строки в новой реплике получились под теми же номерами, что и у предыдущих реплик, нужно при создании реплики указать явные смещения и прогресс, соответствующий этим смещениям.
Опишем способ, как это сделать:
- Отмонтировать реплику-донор и дождаться статуса
unmounted. - Сохранить прогресс репликации (из атрибута
@replication_progressтаблицы-реплики) и использовать его как при создании реплики (передать в атрибуте при созданииchaos_table_replica), так и установить явно на новую таблицу-реплику (с помощьюalter-table). - Для каждого таблета реплики-донора получить число строк в нём - для этого нужно проитерироваться по списку в атрибуте
/@tabletsи собрать поляflushed_row_count. Важно: реплика-донор должа быть всё ещё отмонтирована. - Создать новую реплику, указав ей сохранённый прогресс.
- После того как новая реплика создана, можно примонтировать обратно реплику-донора.
- Создать новую таблицу-реплику, указв при создании число таблетов и нужные смещения через атрибуты
tablet_countиtrimmed_row_counts. Также нужно указатьupstream_replica_idиreplication_progress. - Новую реплику можно монтировать - теперь новые строки будут реплицироваться также и в неё, причём
$row_indexдля них будет таким же, как и для остальных реплик.
Таким способом можно создать новую реплику, консистентную с уже существующими. При этом в ней будут только новые данные. Полноценное копирование мы не рассматриваем по двум причинам: 1) отсутствие remote copy для упорядоченных динтаблиц, 2) сценарий очереди вообще говоря предполагает очистку старых данных и их отсутствие в новой реплике не видится большой проблемой.
Необходимое число очередей репликации
Несмотря на то, что протокол хаосной репликации будет работать при любом числе очередей репликации, в сценарии, когда очередеди разнесены по разным датацентрам, предполагается что очередей как минимум три, и в любой момент времени обязательно должны быть две синхронные.
Если предположить сценарий, в котором, пусть на короткое время, запись идёт только в одну синхронную очередь, то репликация сломается при внезапной недоступности этой очереди. Такая конфигурация может быть допустимой, только если очередь будет находиться на кросс-датацентровом кластере.
Хаос-целлы
Отказоустойчивость и постоянная доступность хаоса достигается благодаря отдельному слою хаосных метаданных, которые располагаются на хаос-целлах. Хаос-целлы располагаюся на кросс-дц кластерах, к томуже информация может быть смигрирована между хаос-целлами при необходимости даунтайма части хаос-целлов (напрмер, при обновлениях).
Как и таблет-целлы, хаос-целлы объединяются в бандлы (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 по идентификатору (не забудтье добавить #).
Пользователь никогда не указывает @replication_card_id для таблиц-реплик. Достаточно указать @upstream_replica_id - идентификатор карточки однозначно выводится из идентификатора реплики.
При создании chaos_replicated_table автоматически создаётся новая карточка репликации. Чтобы создать chaos_replicated_table указывающую на существующую карточку репликации, нужно явно передать её атрибутом replication_card_id при создании.
По умолчанию существование карточки репликации привязывается к хаосной реплицированной динтаблице - при удалении объекта chaos_replicated_table будет автоматически удалена и карточка (это верно как для новых карточек, так и для подцепленных существующих). Изменить это поведение можно с помощью атрибута @owns_replication_card - если выставить false, то карточка останется жить даже после удаления chaos_replicated_table. Важно: такой возможностью нужно пользоваться крайне осторожно и внимательно следить за тем, чтобы всегда была хаосная реплицированная динтаблица, владеющая карточкой. Иначе можно переполнить память хаосных метаданных неактуальными карточками - они ведь так и останутся существовать.
Переключение режимов реплик
Переключение режимов реплик делается командой 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 если для реплики должно быть включено автоматическое переключение режима |