---
metadata:
  - name: generator
    content: Diplodoc Platform v5.50.6
alternate:
  - https://ytsaurus.tech/docs/en/user-guide/dynamic-tables/chaos-dynamic-tables.md
  - https://ytsaurus.tech/docs/ru/user-guide/dynamic-tables/chaos-dynamic-tables.md
---
> **Documentation Index:** Fetch the complete configuration index at https://ytsaurus.tech/docs/ru/llms.txt

<!-- source: ru/_includes/user-guide/dynamic-tables/chaos-dynamic-tables.md -->
## Хаосные реплицированные таблицы

Хаосные реплицированные динтаблицы в YTsaurus функционально похожи на [реплицированные](https://ytsaurus.tech/docs/ru/user-guide/dynamic-tables/replicated-dynamic-tables.md), но основанны на новом протоколе *хаосной репликации*. Как и обычные реплицированные, они позволяют иметь несколько копий одной и той же таблицы на разных кластерах, обновляемых в реальном времени, причём копии строго консистентны друг с другом и вместе представляют постоянно доступную динамическую таблицу с полной поддержкой транзакций.

По сравнению с обычными реплицированными, хаосные динтаблицы всё время доступны и на чтение, и на запись - это достигается благодаря протоколу хаосной репликации. Основные отличия хаосной репликации такие:
- На каждом кластере должна быть реплика специального вида - очередь репликации.
- Репликация делается по pull-модели, при этом в качестве источника может быть использована любая доступная очередь, содержащая достаточно свежие данные.
- Данные о состоянии реплик хранятся на отдельных кластерах *хаосных метаданных* в виде *карточки репликации*
- Для совместимости с обычными реплицированными используется объект `chaos_replicated_table`, который, в отличие от `replicated_table`, не содержит никаких данных - это просто прокси-узел к хаосным метаданным и репликам.
- Хаосные метаданные располагаются в специальном chaos cell bundle. `chaos_replicated_table` подвязывается к хаосному бандлу.
- За счёт изменения топологии репликации меняется подход к [capacity planning](#capacity-planning).

Хаосные реплицированные динтаблицы могут быть как [сортированные](https://ytsaurus.tech/docs/ru/user-guide/dynamic-tables/overview.md), так и [упорядоченные](https://ytsaurus.tech/docs/ru/user-guide/dynamic-tables/ordered-dynamic-tables.md). Для упорядоченных динтаблиц каждая реплика используется и как реплика с данными и как очередь репликации для других реплик. Для сортированных динтаблиц реплики с даными и реплики с очередью репликации - принципиально разные, и имеют разные типы.

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

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

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

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

```bash
yt create chaos_replicated_table //path/to/replicated_table --attr '{
  chaos_cell_bundle=...;
  schema=[...];
}'
```

2. Создание реплики с данными. Это реплика, в которой хранятся сами данные в привычном формате (если отвязать реплику от репликации, это будет обычная динтаблица, со всеми данными). Для того чтобы таблица-реплика получилась привязанной к `chaos_replicated_table`, сперва нужно создать объект вида `chaos_table_replica` - часть метаданных, опиысывающих связь. Он полностью аналогичен `table_replica` для реплицированных динтаблиц. При создании `chaos_table_replica` важно указать к какой `chaos_replicated_table` она относится, а также какую таблицу-реплику описывает. Обратите внимание на `"content_type" = "data"` - это указывает на то, что реплика содержит данные и не может быть использована в качестве источника репликации. Если вы хотите создать реплику упорядоченной динтаблицы нужно указать `"content_type" = "queue"` - тогда реплика будет работать и как реплика с данными, и как источник для репликации.

```bash
$ 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`.

```bash
$ 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
```

3. Создать реплику с очередью репликации (только для сортированных хаосных динтаблиц). Этот шаг аналогичен созданию реплики с данными, но требует указать `"content_type" = "queue"` при создании `chaos_table_replica`, а также использовать тип `replicated_log_table`.

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

```bash
$ 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 replica_cluster 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`. Тогда репликация в реплику продолжится с указанного [прогресса](#progress-replikacii). Этот способ позволяет явно проконтролировать момент, с которого польются реплицированные данные. Подробнее о прогрессе репликации будет ниже.
- Указать прогресс на таблице-реплике. Аналогично предыдущему, репликация продолжится начиная с указанного прогресса. Это наиболее предпочтительный способ, поскольку прогресс явно хранится вместе с таблицей в виде атрибута. **Важно:** прогресс на таблице должен быть больше или равен тому, который указан в `chaos_table_replica`. Если прогресс на таблице вдруг станет меньше, репликация остановится.

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

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

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

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

Так можно скопировать реплику с данными для сортированной хаосной динтаблицы. Реплику-очередь скопировать нельзя, но можно просто создать новую, указав `catchup=%false` - репликация последующих записей будет использовать в том числе и новую реплику-очередь.

### Перемещение реплик

Можно перемещать реплики на новое место с одновременным обновлением пути в карточке репликации. Так как эта операция не атомарная, то, во избежание даунтаймов, рекомендуется предварительно переключить перемещаемую реплику в async-режим.

1. `yt unmount-table <старый путь>`
2. `yt move <старый путь> <новый путь>`
3. `yt alter-table-replica --params '{replica_path="<новый путь>"}' <replica_id>`
4. `yt mount-table <новый путь>`

### Перешардирование реплик-очередей

Реплики-очереди являются очередями, и поэтому нельзя напрямую изменить количество таблетов в таких репликах. Перешардирование реплик-очередей возможно только через пересоздание. Сделать это можно следующим способом:

1. Завести новые реплики-очереди с желаемым количеством шардов в sync-режиме и указав `catchup=%false` и `replicated_table_tracker_enabled=%false` с новым путем. Последнее нужно, чтобы все новые реплики не стали async.
2. Убедиться, что в них началась запись: лаг реплики в интерфейсе должен оставаться околонулевым, а атрибут replication_lag_time должен расти
3. Сгенерировать таймстемп `yt generate-timestamp` и запомнить его
4. Дождаться, когда значение replication_lag_timestamp _всех_ реплик будет больше, чем timestamp, сгенерированный на предыдущем шаге. Посмотреть replication_lag_timestamp реплик таблицы можно командой
```bash
$ yt get "<путь к chaos_replicated_table>/@replicas" | grep replication_lag_timestamp
```
5. Удалить старые реплики-очереди
6. Если нужно, переместить новые реплики на место старых реплик
7. Если нужно, включить автоматику переключение реплик через `alter-table-replica`

### Создание новой реплики для упорядоченной динтаблицы

Реплики упорядоченной динтаблицы представляют собой очереди и самый простой способ - создать новую реплику, указав `catchup=%false` - создаст реплику с работающей репликацией. Однако, в такой реплике номера строк будут отличаться от номеров строк в других репликах, что может привести к неожиданностям при чтении, особенно если `$row_index` указывается явно.

Чтобы строки в новой реплике получились под теми же номерами, что и у предыдущих реплик, нужно при создании реплики указать явные [смещения](https://ytsaurus.tech/docs/ru/user-guide/dynamic-tables/ordered-dynamic-tables.md#sozdanie) и прогресс, соответствующий этим смещениям.

Опишем способ, как это сделать:
1. Отмонтировать реплику-донор и дождаться статуса `unmounted`.
2. Сохранить прогресс репликации (из атрибута `@replication_progress` таблицы-реплики) и использовать его как при создании реплики (передать в атрибуте при создании `chaos_table_replica`), так и установить явно на новую таблицу-реплику (с помощью `alter-table`).
3. Для каждого таблета реплики-донора получить число строк в нём - для этого нужно проитерироваться по списку в атрибуте `/@tablets` и собрать поля `flushed_row_count`. Важно: реплика-донор должа быть всё ещё отмонтирована.
4. Создать новую реплику, указав ей сохранённый прогресс.
5. После того как новая реплика создана, можно примонтировать обратно реплику-донора.
6. Создать новую таблицу-реплику, указв при создании число таблетов и нужные смещения через атрибуты `tablet_count` и `trimmed_row_counts`. Также нужно указать `upstream_replica_id` и `replication_progress`.
7. Новую реплику можно монтировать - теперь новые строки будут реплицироваться также и в неё, причём `$row_index` для них будет таким же, как и для остальных реплик.

Таким способом можно создать новую реплику, консистентную с уже существующими. При этом в ней будут только новые данные. Полноценное копирование мы не рассматриваем по двум причинам: 1) отсутствие remote copy для упорядоченных динтаблиц, 2) сценарий очереди вообще говоря предполагает очистку старых данных и их отсутствие в новой реплике не видится большой проблемой.

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

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

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

## Хаос-целлы {#chaos-cells}

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

Как и таблет-целлы, хаос-целлы объединяются в бандлы (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`.

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

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

Как и обычные реплицированные, хаосные реплицированные таблицы поддерживают [автоматическое переключение реплик](https://ytsaurus.tech/docs/ru/user-guide/dynamic-tables/replicated-dynamic-tables.md#avtomaticheskoe-pereklyuchenie-sinhronnoj-repliki).

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

При создании `chaos_replicated_table` можно указать атрибут `replicated_table_options`, в который передать `ReplicatedTableOptions`. Подробное описание `ReplicatedTableOptions` см в соответствующем [разделе](https://ytsaurus.tech/docs/ru/user-guide/dynamic-tables/replicated-dynamic-tables.md#attributes).

Если хаосная реплицированная динтаблица уже создана, то поменять опции можно с помощью команды `alter_replication_card` (ей нужно передать идентификатор карточки репликации, который указан в атрибуте `@replication_card_id` хаосной реплицированной таблицы и реплик):
```python
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`:
```bash
$ yt alter-table-replica [--enable-replicated-table-tracker | --disable-replicated-table-tracker] replica_id
```

## Capacity Planning

При использовании хаосной репликации подход к capacity planning отличается от обычных реплицированных:
- Вместо одной реплицированной динтаблицы теперь несколько очередей репликации, для каждой нужен резерв под накапливание лага при недоступности других реплик.
- За счёт очередей репликации получается больше реплик, что суммарно даёт больший поток данных
- Репликация потенциально может быть между любой очередью репликации и репликой, и под это должны быть зарезервированы ресурсы для чтения из очереди репликации (в частности, исходящая сеть).
- Объект `chaos_replicated_table`, в отличие от `replicated_table`, данные сам не хранит и не требует ресурсов.

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

## Атрибуты

Атрибуты `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` если для реплики должно быть включено автоматическое переключение режима |
<!-- endsource: ru/_includes/user-guide/dynamic-tables/chaos-dynamic-tables.md -->