Репликация в Reindexer
В Reindexer реализована асинхронная репликация и синхронная с поддержкой RAFT-like алгоритма консенсуса, совместимая с асинхронной.
Журнал упреждающей записи (WAL)
Каждый запрос на изменение данных в Reindexer записывается в журнал упреждающей записи (WAL
), который хранится как часть неймспейса.
Каждая запись в WAL
имеет уникальный 64-битный регистрационный номер (LSN
), который также содержит идентификатор сервера.
Журнал упреждающей записи — это кольцевая структура.
Список перезаписывается после N обновлений (по умолчанию количество записей в WAL
=4000000).
По достижении количества записей N самые старые автоматически удаляются.
WAL
используется для частичной синхронизации между отдельными неймспейсами Leader
и Follower
. Например, в ситуациях временной потери связности между узлами или их перезапуском. В таких случаях Leader
сверяет свой текущий WAL
и WAL
Follower
. Если последняя запись, присутвующая на follower
-ноде всё ещё доступна на Leader
, то будет выполнена попытка последовательного применения отсутвующих записей на Follower
через механизм снэпштов с последующей проверкой контрольных сумм. В случае непредвиденных логических ошибок или, если отставание между узлами слишком велико (превышает wal_size
) для достижения консистетного состояния будет выполнена полная синхронизация неймпейса.
В WAL
записываются только запросы на изменение данных (добавление, обновление, удаление, изменение структуры индексов).
Операции добавления/обновления документов не хранятся как выделенные записи в WAL
, но каждый документ имеет свой собственный LSN
— этого достаточно, чтобы восстановить полный WAL
в оперативной памяти при загрузке неймспейса с диска.
Побочным эффектом этого механизма является отсутствие точной последовательности обновлений индексов и данных.
Поэтому в случае несовместимой миграции данных (например, при изменении типа индексного поля) Follower
вернется к полной синхронизации (force sync
).
Оверхед WAL
равен 18 байтам на каждую запись об изменении данных.
WAL
в Reindexer используется исключительно для механизмов репликации. Он не даёт никаких дополнительных гарантий при записи данных на диск и сам попадает в сторадж асинхронно через LevelDB/RocksDB, как и другие данные.
Полная синхронизация (force sync)
Полная синхронизация подразумевает полное копирование данных во временный неймспейс (его имя будет начинаться с перфикса @tmp_
) и повторное заполнение индексов и дискового стораджа с последующей атомарной заменой старого неймспейса на новый среплицированный. Во-первых, такой вид синхронизации требует дополнтиельной оперативной памяти, достаточной для полной in-memory копии целевого неймспейса, а во-вторых, при большом количестве данных или при проблемах с сетевым соединением force sync
может занимать довольно много времени.
Во время полной синхронизации все модификации неймспейса, происходящие на leader
-ноде, продолжают штатным образом записываться в WAL
, а также накапливаться в очереди онлайн-обновлений. В некоторых ситуациях циклический буфер WAL
и очередь онлайн-обновлений могут переполняться до завершения force sync
. Это приведёт к тому, что процесс полной синхронизации для целевого неймспейса будет запущен повторно. Если такая ситуация возникает регулярно, то следует скорректировать размер WAL
(описано в разделе ниже) и/или размер очередь онлайн-обновлений (задаётся при запуске СУБД, см. CLI-параметр --updatessize
и опцию файла конфигурации net.maxupdatessize
в разделе конфигурации)
Настройка максимального количества записей в WAL
По умолчанию количество записей в WAL
=4000000.
Его можно изменить через Reindexer Face, утилиту reindexer_tool
или с помощью операции upsert по HTTP или через коннектор.
Этот параметр меняется в поле wal_size
объекта namespaces
служебного неймспейса #config
:
{
"type": "namespaces",
"namespaces": [
{
"namespace": "*",
"log_level": "none",
"lazyload": false,
"unload_idle_threshold": 0,
"join_cache_mode": "off",
"start_copy_policy_tx_size": 10000,
"copy_policy_multiplier": 5,
"tx_size_to_always_copy": 100000,
"optimization_timeout_ms": 800,
"optimization_sort_workers": 4,
"wal_size": 4000000,
"min_preselect_size": 1000,
"max_preselect_size": 1000,
"max_preselect_part": 0.1
}
]
}
Просмотр WAL неймспейса
Для просмотра содержимого WAL
неймспейса используется оператор SELECT со специальным условием для индекса #lsn
:
SELECT * FROM test_namespace WHERE #lsn > 1000
curl --location --request POST 'http://127.0.0.1:5000/api/v1/db/testdb/query' \
--header 'Content-Type: application/json' \
--data-raw '{
"namespace": "test_namespace",
"type": "select",
"filters": [
{
"field": "#lsn",
"cond": "GT",
"value": 1000
}
]
}'
Reindexer> SELECT * FROM test_namespace where #lsn > 1000
Для вывода всех записей WAL
можно воспользоваться условием #lsn is not null
.
Также для ограничения выдачи возможно использование параметров LIMIT
и OFFSET
.
Настройка общих параметров репликации
Эти параметры являются общими, как для асинхронной, так и для синхронной репликации.
Общие параметры репликации можно задать одним из двух способов:
- в служебном неймспейсе
#config
, - в файле конфигурации
replication.conf
.
Настройка общих параметров репликации в служебном неймспейсе #config
Общие параметры репликации задаются в служебном неймспейсе #config в поле replication
:
{
"type": "replication",
"replication": {
"server_id": 0,
"cluster_id": 2,
"admissible_replication_tokens":[
{
"token":"<some_token_1>",
"namespaces":["ns1"]
},
{
"token":"<some_token_2>",
"namespaces":["ns2", "ns3"]
},
{
"token":"<some_token_3>",
"namespaces":["ns4"]
}
]
}
}
Здесь:
-
server_id
— уникальный идентификатор сервера (ноды). Должен быть задан пользователем. -
cluster_id
— номер группы (или кластера), в которой участвует нода. Должен быть одинаковым для всех нод группы (кластера). -
admissible_replication_tokens
— Опциональный объект со списками неймспейсов и токенами, которыеfollower
ожидает от подключающихся лидеров. Если для неймспейса задан какой-либоadmissible
-токен, то лидер сможет среплицировать его на текущую ноду, только еслиadmissible
-токен совпадает сself_replication_token
, сконфигурированным наleader
-ноде. В примере выше:{ "token":"<some_token_2>", "namespaces":["ns2", "ns3"] }
означает, что репликация для неймспейсов
ns2
иns3
будет осуществляться, только если в конфигурацииleader
-а задано соответствующее значение токена:self_replication_token: <some_token_2>
.Каждый неймспейс может иметь только один токен.
Для указания общего
admissible
-токена для всех неймспейсов можно использовать следующую запись:"admissible_replication_tokens":[ { "token":"<some_common_token>", "namespaces":["*"] }, { "token":"<some_token_1>", "namespaces":["ns1"] } ]
Эта запись означает, что для
ns1
ожидается токен<some_token_1>
, а для остальных<some_common_token>
.(Доступно с версии
v5.2.0
)
Настройка общих параметров репликации в файле конфигурации replication.conf
Общие параметры репликации настраиваются в файле replication.conf
в формате YAML.
Его необходимо разместить в директории реплицируемой базы данных.
Файл replication.conf
считывается при старте СУБД.
Если в этот момент он существует, то его содержимое будет синхронизироваться в рантайме со служебным неймспейсом #config
: то, что записано в файл, будет перенесено в неймспейс, и наоборот.
Если же файла нет в директории реплицируемой базы данных при старте сервера, будут применяться настройки репликации из неймспейса #config
, а содержимое добавленного replication.conf
будет игнорироваться до перезапуска.
При этом, если файла нет при старте сервера, создаваться автоматически он не будет.
Содержимое файла конфигурации аналогично содержимому поля replication
служебного неймспейса config
.
Пример файла конфигурации для настройки общих параметров репликации.
Проверка целостности данных
Существуют потенциальные риски нарушения согласованности данных между Leader
-ом и Follower
-ом в ходе репликации.
Для их исключения Reindexer вычисляет легкий инкрементный хеш всех данных неймспейса (DataHash), который используется для быстрой проверки, что данные Follower
действительно совпадают с Leader
.
При обнаружении расхождения данных DataHash происходит повторная полная синхронизация.