Асинхронная репликация

Reindexer поддерживает механизм асинхронной репликации. У каждого экземпляра сервера, задействованного в репликации, может быть роль Leader или Follower. В качестве Leader может выступать сервер Reindexer Standalone, Built-in, Built-in server (подробнее о вариантах использования — в разделе «Установка Reindexer»). Роль Follower может быть у сервера Standalone и Built-in server: Leader-у нужен доступ к RPC-интерфейсам Follower-ов.

Начиная с версии 4.x.x в Reindexer реализована push-репликация. При таком механизме Leader инициирует отправку сведений об изменениях Follower-ам. В версии 3.x.x использовался механизм асинхронной pull-репликации. При переходе с Reindexer 3.x.x на 4.x.x ряд настроек необходимо выполнить вручную (подробнее — в разделе Настройки асинхронной репликации при миграции с Reindexer версии 3.x.x на 4.x.x).

Механизмы асинхронной репликации в Reindexer

Для реализации репликации в Reindexer используется 3 различных механизма:

Механизм Когда используется Особенности
Полная синхронизация с использованием снимка неймспейса (force-sync) 1. При начальной синхронизации для копирования полной структуры и данных из неймспейса Leader в Follower или от одного Follower к другому.
2. В случае ошибки с репликацией WAL (например, WAL устарел, или появились несовместимые изменения в структуре индексов)
В этом режиме Leader создает моментальный снэпшот неймспейса (используется стратегия COW) и отправляет все свои индексы и данные Follower
Запись из локального журнала WAL (wal-sync) Когда Leader устанавливает сетевое соединение с Follower для синхронизации данных (например, при потере связи с Follower) Leader запрашивает LSN из WAL Follower-а, делает запрос к своему локальному WAL (каждая запись в нем — это информация про отдельный документ, либо update/delete-запрос), на выходе формирует снэпшот, содержащий только недостающие записи из WAL, и применяет из него все записи. В результате все данные в WAL Leader и Follower совпадают
Онлайн-обновления WAL в реальном времени (онлайн репликация) Когда установлено соединение между Leader и Follower Leader отправляет поток обновлений WAL на всех подключенных Follower-ов. Этот режим требует меньше ресурсов процессора и памяти Leader

Каскадная репликация

Reindexer также поддерживает каскадную репликацию. В этом случае может быть только один Leader. Но у Follower-ов могут быть свои Follower-ы:

             Leader
           /        \
 Follower1           Follower2
     |                /     \
Follower1.1   Follower2.1 Follower2.2

На этой схеме Follower1 и Follower2 реплицируют данные своим Follower-ам, но при этом не предоставляют возможность изменения данных для внешних клиентов.

Настройка асинхронной репликации в Reindexer, начиная с версии 4.x.x

Настройка репликации в Reindexer возможна двумя способами: через служебный неймспейс #config и с помощью файлов конфигурации.

Настройка репликации через служебный неймспейс #config

Репликация настраивается на стороне Leader. Для этого в служебном неймспейсе #config:

  1. Задаются общие параметры репликации. Подробнее — в разделе «Настройка общих параметров репликации».

  2. Устанавливаются специальные параметры для асинхронной репликации.

Настройка специальных параметров асинхронной репликации

Специальные параметры для асинхронной репликации задаются в служебном неймспейсе #config ноды-Leader, в айтеме async_replication:

{
  "type": "async_replication",
  "async_replication": {
    "role": "none",
    "sync_threads": 4,
    "syncs_per_thread": 2,
    "online_updates_timeout_sec": 20,
    "online_updates_delay_msec": 100,
    "sync_timeout_sec": 60,
    "retry_sync_interval_msec": 30000,
    "enable_compression": true,
    "batching_routines_count": 100,
    "force_sync_on_logic_error": false,
    "force_sync_on_wrong_data_hash": false,
    "log_level": "info",
    "max_wal_depth_on_force_sync": 1000,
    "namespaces": [],
    "nodes": [
      {
        "dsn": "cproto://192.168.1.5:6534/mydb",
        "namespaces": []
      }
    ]
  }
}

Здесь:

  • role — роль экземпляра сервера в репликации. Возможные значения:

    • none — репликация отключена,
    • follower — сервер участвует в репликации как Follower,
    • leader — сервер участвует в репликации как Leader.
  • sync_threads — количество потоков репликации.

  • syncs_per_thread — Максимальное количество одновременных полных синхронизаций для каждого потока репликации.

  • online_updates_timeout_sec — время ожидания ответа от Follower для режима онлайн-репликации. Задается в секундах.

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

  • sync_timeout_sec — время на запись чанка из снэпшота. Если запись не произошла за это время, то соединение разрывается и происходит полная синхронизация. Задается в секундах.

  • retry_sync_interval_msec — таймаут повторной попытки синхронизации при возникновении сетевых ошибок.

  • enable_compression — флаг для включения/отключения сжатия сетевого трафика.

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

  • log_level — уровень логирования репликатора при запуске. Возможные значения: none, error, warning, info, trace.

  • max_wal_depth_on_force_sync — максимальное количество записей WAL, которые будут скопированы после запуска полной синхронизации. Увеличение значения этого параметра может помочь избежать force-syncs синхронизации после переключения Leader, а также увеличивает расход оперативной памяти во время синхронизации.

  • online_updates_delay_msec — задержка реплицирования для онлайн-репликации. Использование этой задержки позволяет значительно сократить потребление CPU за счёт объединения отдельных записей в батчи (по умолчанию используется задежрка 100 мс). Напрямую влияет на время, за которое одиночные записи реплицируются на Follower-ов. Задаётся в милисекундах.

  • namespaces — список неймспейсов для репликации. Если он пустой, будет выполняться репликация всех неймспейсов из базы данных. Все реплицируемые неймспейсы на Follower-ах будут иметь режим read-only.

  • nodes — список Follower-ов и их настройки:

    • dsn — DSN ноды—Follower-а. Должен задаваться в cproto-формате. Содержит адрес и порт для доступа к Follower по протоколу RPC и имя БД Follower, в которую будут реплицироваться данные.
    • namespaces — необязательный список неймспейсов для репликации на данную ноду-Follower. Если он не задан, будет использоваться значение из общей конфигурации репликации.

Настройка репликации с помощью файлов конфигурации

При этом способе настройки используются YAML-файлы конфигурации:

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

Файлы replication.conf и async_replication.conf считываются при старте СУБД. Если в этот момент они существуют, то их содержимое будет синхронизироваться в рантайме со служебным неймспейсом #config: то, что записано в файлы, будет перенесено в неймспейс, и наоборот.

Если же файлов нет в директории реплицируемой базы данных при старте сервера, будут применяться настройки репликации из неймспейса #config, а содержимое добавленных replication.conf и async_replication.conf будет игнорироваться до перезапуска. При этом, если файлов нет при старте сервера, создаваться автоматически они не будут.

Содержимое файла конфигурации replication.conf аналогично содержимому поля replication служебного неймспейса config. Пример файла конфигурации для настройки общих параметров репликации.

Содержимое файла конфигурации async_replication.conf аналогично содержимому поля async_replication служебного неймспейса config. Пример файла конфигурации для настройки специальных параметров асинхронной репликации.

Проверка статуса репликации

Сведения о статусе репликации доступны в служебном неймспейсе #memstats. Пример запроса для их получения через reindexer_tool:

Reindexer> SELECT name,replication FROM #memstats WHERE name='media_items'

В ответ вернется JSON-объект со сведениями о статусе репликации для неймспейса (в примере выше проверяется статус репликации для неймспейса media_items):

{
  "items": [
    {
      "name": "media_items",
      "replication": {
        "last_lsn": 3,
        "last_lsn_v2": {
          "server_id": 0,
          "counter": 3
        },
        "temporary": false,
        "incarnation_counter": 0,
        "data_hash": 6806236826,
        "data_count": 3,
        "updated_unix_nano": 1655797373139806200,
        "ns_version": {
          "server_id": 0,
          "counter": 9
        },
        "clusterization_status": {
          "leader_id": 0,
          "role": "simple_replica"
        },
        "wal_count": 3,
        "wal_size": 108
      }
    }
  ],
  "namespaces": [
    "#memstats"
  ],
  "cache_enabled": false
}

Здесь:

  • last_lsn — (deprecated-поле) Значение LSN.

  • last_lsn_v2: - LSN последней операции по изменению данных неймспейса на ноде. При репликации значения LSN для каждой записи Leader и Follower будут иметь одинаковые значения.

    • server_id — id ноды, являющейся источником этого LSN.
    • counter — количество LSN на ноде.
  • temporary — флаг, указывающий, является ли неймспейс временным.

  • incarnation_counter — количество переключений между Leader и Follower.

  • data_hash — хэш данных неймспейса.

  • data_count — количество записей в неймспейсе.

  • updated_unix_nano — время выполнения последнего обновления данных.

  • ns_version:

    • server_id — id ноды, id ноды, являющейся источником этого LSN.
    • counter — текущая версия неймспейса.
  • clusterization_status:

    • leader_id — server_id ноды, которая является лидером для этой реплики,
    • role — текущая роль в репликации. Возможные значения:
      • simple_replica — асинхронная read-only реплика;
      • cluster_replica — один из Follower-ов в синхронном RAFT-кластере;
      • noneLeader в асинхронной репликации, в синхронном кластере, либо неймспейс не участвует в репликации.
  • wal_count — количество записей в WAL.

  • wal_size — размер WAL.

Интерактивное управление репликацией

В Reindexer также поддерживается несколько команд для интерактивного управления репликацией через reindexer_tool или веб-интерфейс.

Перезапуск репликации

При отправке запроса на Leader процесс репликации перезапускается полностью. Пример запроса через reindexer_tool

Reindexer> \upsert #config { "type":"action","action":{ "command":"restart_replication" } }

Сброс роли в репликации

Команда будет полезна, если вы хотите отменить участие Follover-а в репликации и сделать его неймспейсы доступными для изменения, отключив режим read-only. Пример запроса для сброса роли в репликации через reindexer_tool:

Reindexer> \upsert #config { "type":"action","action":{ "command":"reset_replication_role" } }

Сброс роли в репликации для определенного неймспейса

Позволяет отключить на Follower-е репликацию определенного неймспейса и сделать его доступным для изменения (отключить режим read-only). Пример запроса через reindexer_tool:

Reindexer> \upsert #config { "type":"action","action":{ "command":"reset_replication_role", "namespace": "ns_name" } }

Помимо сброса роли в репликации (в том числе и для определенного неймспейса) и отключения режима read-only для ноды, ее нужно вывести из репликации в настройках Leader. Для этого удалите данного Follower-а из поля nodes в неймспейсе #config Leader-а. Если этого не сделать, произойдет force-sync и нода снова станет Follower-ом.

Управление уровнем логирования репликатора

Команда позволяет менять уровень логирования асинхронного и кластерного (синхронного) репликаторов без их перезапуска. Логирование осуществляется через core-логгер, поэтому для info/trace-логов репликатора требуется уровень core-логирования не ниже, чем info.

Reindexer> \upsert #config { "type":"action","action":{ "command":"set_log_level", "type": "async_replication", "level":"trace" } }

Возможные значения types:

  • async_replication (для логов асинхронного репликатора),
  • cluster (для логов синхронного репликатора и логов RAFT).

Возможные значения levels:

  • none,
  • error,
  • warning,
  • info,
  • trace.

Настройки асинхронной репликации при миграции с Reindexer версии 3.x.x на 4.x.x

В версии Reindexer 3.x.x была реализована асинхронная pull-репликация. Ее настройки несовместимы с настройками репликации Reindexer 4.x.x. Поэтому вам придется выполнить конфигурацию вручную.

Для этого требуется ряд изменений в объектах replication и async_replication в служебных неймспейсах #config. Id серверов и кластеров в объекте replication служебного неймспейса #config для Leader-а и Follower-ов изменять при этом не нужно.

Пример миграции для одноуровневой схемы асинхронной репликации

В качестве примера рассмотрим миграцию для следующей схемы репликации:

              leader(192.168.10.1)
             /                  \
   follower1(192.168.10.2)   follower2(192.168.10.3)

Настройки для follower1

Настройки репликации для follower1 в объекте replication:

{
  "type":"replication",
  "replication":{
  	"role":"slave",
  	"master_dsn":"cproto://192.168.10.1/db",
  	"cluster_id":2,
  	"server_id":1,
  	"force_sync_on_logic_error": false,
  	"force_sync_on_wrong_data_hash": false,
  	"namespaces":
  	  - "ns1"
  }
}
{
  "type": "replication",
  "replication": {
    "cluster_id": 2,
    "server_id": 1
  }
}

Deprecated параметры должны быть удалены из настроек Follower-а.

Reindexer> \upsert #config { "type": "replication", "replication": { "server_id": 1, "cluster_id": 2 } }

Настройки для follower2

Настройки репликации для follower2 в объекте replication:

{
  "type":"replication",
  "replication":{
  	"role":"slave",
  	"master_dsn":"cproto://192.168.10.3/db",
  	"cluster_id":2,
  	"server_id":2,
  	"force_sync_on_logic_error": false,
  	"force_sync_on_wrong_data_hash": false,
  	"namespaces":
  	  - "ns2"
  	  - "ns3"
  }
}
{
  "type": "replication",
  "replication": {
    "cluster_id": 2,
    "server_id": 2
  }
}

Deprecated-параметры должны быть удалены из настроек Follower-а.

Reindexer> \upsert #config { "type": "replication", "replication": { "server_id": 2, "cluster_id": 2 } }

Настройки для всех Follower

В ходе миграции для всех Follower-ов нужно задать роль follower в объекте async_replication служебного неймспейса #config:

{
  "type": "async_replication",
  "async_replication": {
    "role": "follower"
  }
}

Пример запроса на изменение настроек через reindeхer_tool:

Reindexer> \upsert #config { "type": "async_replication", "async_replication": { "role":"follower" } }

Настройки для Leader

Настройки репликации для leader в объекте replication:

{
  "type": "replication",
  "replication": {
    "role": "master",
    "master_dsn": "",
    "cluster_id": 2,
    "server_id": 0
  }
}
{
  "type": "replication",
  "replication": {
    "cluster_id": 2,
    "server_id": 0
  }
}
Reindexer> \upsert #config { "type": "replication", "replication": { "server_id": 0, "cluster_id": 2 } }
Настройки репликации для leader в объекте async_replication для Reindexer 4.x.x:

Для leader в ходе миграции нужно создать новую конфигурацию в объекте async_replication служебного неймспейса #config:

{
  "type": "async_replication",
  "async_replication": {
    "role": "leader",
    "sync_threads": 4,
    "syncs_per_thread": 2,
    "online_updates_timeout_sec": 60,
    "retry_sync_interval_msec": 30000,
    "enable_compression": true,
    "batching_routines_count": 100,
    "force_sync_on_logic_error": false,
    "force_sync_on_wrong_data_hash": false,
    "namespaces": [],
    "nodes": [
      {
        "dsn": "cproto://192.168.10.2:6534/mydb",
        "namespaces": [
          "ns1"
        ]
      },
      {
        "dsn": "cproto://192.168.10.3:6534/mydb",
        "namespaces": [
          "ns2",
          "ns3"
        ]
      }
    ]
  }
}

Пример НТТР-запроса для создания новой конфигурации:

curl --location --request PATCH 'http://192.168.10.1/api/v1/db/testdb/namespaces/%23config/items' \
--header 'Content-Type: application/json' \
--data-raw '{
  "type": "async_replication",
  "async_replication": {
    "role": "leader",
    "sync_threads": 4,
    "syncs_per_thread": 2,
    "online_updates_timeout_sec": 60,
    "retry_sync_interval_msec": 30000,
    "enable_compression": true,
    "batching_routines_count": 100,
    "force_sync_on_logic_error": false,
    "force_sync_on_wrong_data_hash": false,
    "namespaces": [],
    "nodes": [
      {
        "dsn": "cproto://192.168.10.2:6534/mydb",
        "namespaces": [
          "ns1"
        ]
      },
      {
        "dsn": "cproto://192.168.10.3:6534/mydb",
        "namespaces": [
          "ns2",
          "ns3"
        ]
      }
    ]
  }
}'

Миграция с Reindexer версии 3.x.x на 4.x.x при использовании каскадной асинхронной репликации

Миграция для каскадной репликации не сильно отличается от миграции для других схем. Как и в случае с одноуровневой схемой репликации, потребуется изменить конфигурацию в объектах replication и async_replication в служебных неймспейсах #config нод.

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

   leader(192.168.10.1)
             |
   follower1(192.168.10.2)
             |
   follower2(192.168.10.3)

Настройки для follower1

Объект replication неймспейса #config для follower1:

{
  "type": "replication",
  "replication": {
    "role": "slave",
    "master_dsn": "cproto://192.168.10.1/db",
    "cluster_id": 2,
    "server_id": 1,
    "force_sync_on_logic_error": false,
    "force_sync_on_wrong_data_hash": false,
    "namespaces": []
  }
}
{
  "type": "replication",
  "replication": {
    "cluster_id": 2,
    "server_id": 1
  }
}

Так как follower1 будет выступать в роли Leader-а для follower2 из примера, для него нужно еще задать настройки в объекте async_replication неймспейса #config:

{
  "type": "async_replication",
  "async_replication": {
    "role": "leader",
    "sync_threads": 4,
    "syncs_per_thread": 2,
    "online_updates_timeout_sec": 60,
    "retry_sync_interval_msec": 30000,
    "enable_compression": true,
    "batching_routines_count": 100,
    "force_sync_on_logic_error": false,
    "force_sync_on_wrong_data_hash": false,
    "namespaces": [],
    "nodes": [
      {
        "dsn": "cproto://192.168.10.3:6534/mydb"
      }
    ]
  }
}

Обратите внимание, что в настройках follower1 (который выступает в роли Leader для follower2) в nodes не указывается список неймспейсов для репликации для конкретной ноды-Follower. Список неймспейсов для репликации берется из массива namespaces объекта async_replication.

Настройки для follower2

Объект replication неймспейса #config для follower2:

{
	"type":"replication",
	"replication":{
		"role":"slave",
		"master_dsn":"cproto://192.168.10.2/db",
		"cluster_id":2,
		"server_id":2,
		"force_sync_on_logic_error": false,
		"force_sync_on_wrong_data_hash": false,
		"namespaces": []
	}
}
{
  "type": "replication",
  "replication": {
    "cluster_id": 2,
    "server_id": 2
  }
}

Также для follower2 нужно установить соответствующую роль в объекте async_replication неймспейса #config:

{
  "type": "replication",
  "async_replication": {
    "role": "follower"
  }
}

Настройки для leader

Объект replication неймспейса #config для leader:

{
  "type": "replication",
  "replication": {
    "role": "master",
    "master_dsn": "",
    "cluster_id": 2,
    "server_id": 0
  }
}
{
  "type": "replication",
  "replication": {
    "cluster_id": 2,
    "server_id": 0
  }
}

Настройки для leader в объекте async_replication неймспейса #config:

{
  "type": "async_replication",
  "async_replication": {
    "role": "leader",
    "sync_threads": 4,
    "syncs_per_thread": 2,
    "online_updates_timeout_sec": 60,
    "retry_sync_interval_msec": 30000,
    "enable_compression": true,
    "batching_routines_count": 100,
    "force_sync_on_logic_error": false,
    "force_sync_on_wrong_data_hash": false,
    "namespaces": [],
    "nodes": [
      {
        "dsn": "cproto://192.168.10.2:6534/mydb"
      }
    ]
  }
}