Версия:

Руководство пользователя / Репликация / Добавление экземпляров
Руководство пользователя / Репликация / Добавление экземпляров

Добавление экземпляров

Добавление экземпляров

Добавление реплики

../../../_images/mr-1m-2r-mesh-add.png

Чтобы добавить вторую реплику в набор реплик с конфигурацией мастер-реплика из нашего примера настройки, необходим аналог файла экземпляра, который мы создали для первой реплики в этом наборе:

-- файл экземпляра для реплики №2
box.cfg{
  listen = 3301,
  replication = {'replicator:password@192.168.0.101:3301',  -- URI мастера
                 'replicator:password@192.168.0.102:3301',  -- URI реплики №1
                 'replicator:password@192.168.0.103:3301'}, -- URI реплики №2
  read_only = true
}
box.once("schema", function()
   box.schema.user.create('replicator', {password = 'password'})
   box.schema.user.grant('replicator', 'replication') -- предоставить роль для репликации
   box.schema.space.create("test")
   box.space.test:create_index("primary")
   print('box.once executed on replica #2')
end)

Здесь мы добавляем URI реплики №2 в параметр replication, так что теперь он содержит три URI.

После запуска новая реплика подключается к мастер-серверу и получает от него журнал упреждающей записи и файлы снимков:

$ # запуск реплики №2
$ tarantool replica2.lua
2017-06-14 14:54:33.927 [46945] main/101/replica2.lua C> version 1.7.4-52-g980d30092
2017-06-14 14:54:33.927 [46945] main/101/replica2.lua C> log level 5
2017-06-14 14:54:33.928 [46945] main/101/replica2.lua I> mapping 268435456 bytes for tuple arena...
2017-06-14 14:54:33.930 [46945] main/104/applier/replicator@192.168.0.10 I> remote master is 1.7.4 at 192.168.0.101:3301
2017-06-14 14:54:33.930 [46945] main/104/applier/replicator@192.168.0.10 I> authenticated
2017-06-14 14:54:33.930 [46945] main/101/replica2.lua I> bootstrapping replica from 192.168.0.101:3301
2017-06-14 14:54:33.933 [46945] main/104/applier/replicator@192.168.0.10 I> initial data received
2017-06-14 14:54:33.933 [46945] main/104/applier/replicator@192.168.0.10 I> final data received
2017-06-14 14:54:33.934 [46945] snapshot/101/main I> saving snapshot `/var/lib/tarantool/replica2/00000000000000000010.snap.inprogress'
2017-06-14 14:54:33.934 [46945] snapshot/101/main I> done
2017-06-14 14:54:33.935 [46945] main/101/replica2.lua I> vinyl checkpoint done
2017-06-14 14:54:33.935 [46945] main/101/replica2.lua I> ready to accept requests
2017-06-14 14:54:33.935 [46945] main/101/replica2.lua I> set 'read_only' configuration option to true
2017-06-14 14:54:33.936 [46945] main C> entering the event loop

Поскольку мы добавляем экземпляр только для чтения (read-only), нет необходимости в динамическом обновлении параметра replication на других работающих экземплярах. Такое обновление необходимо, если бы мы добавляли мастера.

Тем не менее, рекомендуем указать URI реплики №3 во всех файлах экземпляра в наборе реплик. Это поможет сохранить единообразие файлов и согласовать их с текущей топологией репликации, а также не допустить ошибок конфигурации в случае последующего обновления конфигурации и перезапуска набора реплик.

Добавление мастера

../../../_images/mm-3m-mesh-add.png

Чтобы добавить третьего мастера в набор реплик с конфигурацией мастер-мастер из нашего примера настройки, необходим аналог файлов экземпляров, которые мы создали для настройки других мастеров в этом наборе:

-- файл экземпляра для мастера №3
box.cfg{
  listen      = 3301,
  replication = {'replicator:password@192.168.0.101:3301',  -- URI мастера №1
                 'replicator:password@192.168.0.102:3301',  -- URI мастера №2
                 'replicator:password@192.168.0.103:3301'}, -- URI мастера №3
  read_only   = true, -- временно только для чтения
}
box.once("schema", function()
   box.schema.user.create('replicator', {password = 'password'})
   box.schema.user.grant('replicator', 'replication') -- выдача роли для репликации
   box.schema.space.create("test")
   box.space.test:create_index("primary")
end)

Здесь мы вносим следующие изменения:

  • Добавить URI мастера №3 в параметр replication.
  • Временно укажите read_only=true, чтобы отключить операции по изменению данных на этом экземпляре. После запуска мастер №3 будет работать в качестве реплики, пока не получит все данные от других мастеров в наборе реплик.

После запуска мастер №3 подключается к другим мастер-экземплярам и получает от них файлы журнала упреждающей записи и файлы снимков:

$ # запуск мастера №3
$ tarantool master3.lua
2017-06-14 17:10:00.556 [47121] main/101/master3.lua C> version 1.7.4-52-g980d30092
2017-06-14 17:10:00.557 [47121] main/101/master3.lua C> log level 5
2017-06-14 17:10:00.557 [47121] main/101/master3.lua I> mapping 268435456 bytes for tuple arena...
2017-06-14 17:10:00.559 [47121] iproto/101/main I> binary: bound to [::]:3301
2017-06-14 17:10:00.559 [47121] main/104/applier/replicator@192.168.0.10 I> remote master is 1.7.4 at 192.168.0.101:3301
2017-06-14 17:10:00.559 [47121] main/105/applier/replicator@192.168.0.10 I> remote master is 1.7.4 at 192.168.0.102:3301
2017-06-14 17:10:00.559 [47121] main/106/applier/replicator@192.168.0.10 I> remote master is 1.7.4 at 192.168.0.103:3301
2017-06-14 17:10:00.559 [47121] main/105/applier/replicator@192.168.0.10 I> authenticated
2017-06-14 17:10:00.559 [47121] main/101/master3.lua I> bootstrapping replica from 192.168.0.102:3301
2017-06-14 17:10:00.562 [47121] main/105/applier/replicator@192.168.0.10 I> initial data received
2017-06-14 17:10:00.562 [47121] main/105/applier/replicator@192.168.0.10 I> final data received
2017-06-14 17:10:00.562 [47121] snapshot/101/main I> saving snapshot `/Users/e.shebunyaeva/work/tarantool-test-repl/master3_dir/00000000000000000009.snap.inprogress'
2017-06-14 17:10:00.562 [47121] snapshot/101/main I> done
2017-06-14 17:10:00.564 [47121] main/101/master3.lua I> vinyl checkpoint done
2017-06-14 17:10:00.564 [47121] main/101/master3.lua I> ready to accept requests
2017-06-14 17:10:00.565 [47121] main/101/master3.lua I> set 'read_only' configuration option to true
2017-06-14 17:10:00.565 [47121] main C> entering the event loop
2017-06-14 17:10:00.565 [47121] main/104/applier/replicator@192.168.0.10 I> authenticated

Затем добавляем URI мастера №3 в параметр replication на существующих мастерах. В конфигурации репликации используются динамические параметры, поэтому необходимо только выполнить запрос box.cfg{} на каждом работающем экземпляре:

# добавление URI мастера №3 в источники репликации
tarantool> box.cfg{replication =
         > {'replicator:password@192.168.0.101:3301',
         > 'replicator:password@192.168.0.102:3301',
         > 'replicator:password@192.168.0.103:3301'}}
---
...

Когда мастер №3 получает все необходимые изменения от других мастеров, можно отключить режим только для чтения:

# назначение мастера №3 настоящим мастером
tarantool> box.cfg{read_only=false}
---
...

Также рекомендуется указать URI мастера №3 во всех файлах экземпляра, чтобы сохранить единообразие файлов и согласовать их с текущей топологией репликации.

Статус orphan (одиночный)

Начиная с версии Tarantool’а 1.9, процедура подключения реплики к набору реплик изменяется. Во время box.cfg() экземпляр попытается подключиться ко всем мастерам, указанным в box.cfg.replication. Если не было успешно выполнено подключение к количеству мастеров, указанному в replication_connect_quorum, экземпляр переходит в статус orphan (одиночный). Когда экземпляр находится в статусе orphan, он доступен только для чтения.

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

«Установка соединения» означает контакт с мастером по физической сети и получение подтверждения. Если нет подтверждения соединения через box.replication_connect_timeout секунд (обычно 4 секунды), и повторные попытки подключения не сработали, то соединение не установлено.

«Синхронизация» означает получение обновлений от мастера для создания локальной копии базы данных. Синхронизация завершена, когда реплика получила все обновления или хотя бы получила достаточное количество обновлений, чтобы отставание реплики (см. replication.upstream.lag в box.info()) было меньше или равно количеству секунд, указанному в box.cfg.replication_sync_lag. Если значение replication_sync_lag не задано (nil) или указано как «TIMEOUT_INFINITY», то реплика пропускает шаг «синхронизация» и сразу же переходит на «отслеживание».

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

  • Уменьшить значение replication_connect_quorum.
  • Убрать из списка box.cfg.replication недоступные и прочие узлы, с которыми нельзя синхронизироваться.
  • Вообще задать "" (пустую строку) в качестве значения``box.cfg.replication``.

Возможны следующие ситуации.

Ситуация 1: настройка

Здесь впервые происходит вызов box.cfg{}. Реплика подключается, но набора реплик пока нет.

  1. Установка статуса „orphan“ (одиночный).

  2. Попытка установить соединение со всеми узлами из box.cfg.replication или с количеством узлов, указанным в параметре replication_connect_quorum. Допускаются три повторные попытки за 30 секунд, поскольку идет стадия настройки, параметр replication_connect_timeout не учитывается.

  3. Прекращение работы и выдача ошибки в случае отсутствия соединения со всеми узлами в box.cfg.replication или replication_connect_quorum.

  4. Экземпляр может быть выбран в качестве лидера „leader“ в наборе реплик. Критерии выбора лидера включают в себя значение vclock (чем больше, тем лучше), а также доступность только для чтения или для чтения и записи (лучше всего для чтения и записи, кроме случаев, когда других вариантов нет). Лидер является мастером, к которому должны подключиться другие экземпляры. Лидер является мастером, который выполняет функции box_once().

  5. Если данный экземпляр выбран лидером набора реплик, выполняется «самонастройка»:

    1. Установка статуса „running“ (запущен).
    2. Возврат из box.cfg{}.

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

    1. Настройка от лидера. См. примеры в разделе Настройка набора реплик.
    2. Синхронизация со всеми остальными узлами в наборе реплик в фоновом режиме.

Ситуация 2: восстановление

Здесь вызов box.cfg{} происходит не впервые, а повторно для осуществления восстановления.

  1. Проведение восстановления из последнего локального снимка и WAL-файлов.
  2. Установить соединение с количеством узлов не меньшим, чем replication_connect_quorum. Если не получается - установить статус „orphan“. (Попытки синхронизации будут повторяться в фоновом режиме, и когда/если они окажутся успешными, статус „orphan“ сменится на „connected“.)
  3. Если соединение установлено - осуществлять синхронизацию со всеми подключенными узлами до тех пор, пока отличия не будут более replication_sync_lag секунд.

Ситуация 3: обновление конфигурации

Здесь вызов box.cfg{} происходит не впервые, а повторно, поскольку изменились некоторые параметры репликации или что-то в наборе реплик.

  1. Попытка установить соединение со всеми узлами из box.cfg.replication или с количеством узлов, указанным в параметре replication_connect_quorum в течение периода времени, указанного в replication_connect_timeout.
  2. Попытка синхронизации со всеми подключенными узлами в течение периода времени, указанного в replication_sync_timeout.
  3. Если предыдущие шаги не выполнены, статус изменяется на „orphan“ (одиночный). (Попытки синхронизации будут продолжаться в фоновом режиме, и когда/если они будут успешны, статус „orphan“ отключится.)
  4. Если предыдущие шаги выполнены, статус изменяется на „running“ (мастер) или „follow“ (реплика).

Ситуация 4: повторная настройка

Здесь не происходит вызов box.cfg{}. В определенный момент в прошлом реплика успешно установила соединение и в настоящий момент ожидает обновления от мастера. Однако мастер не может передать обновления, что может произойти случайно, или же если реплика работает слишком медленно (большое значение lag), а WAL-файлы (.xlog) с обновлениями были удалены. Такая ситуация не является критической – реплика может сбросить ранее полученные данные, а затем запросить содержание последнего файла снимка (.snap) мастера. Поскольку фактически в таком случае повторно проводится процесс настройки, это называется «повторная настройка». Тем не менее, есть отличие от обычной настройки – идентификатор реплики останется прежним. Если он изменится, то мастер посчитает, что в кластер добавляется новая реплика, и сохранит идентификатор экземпляра реплики, которой уже не существует. Полностью автоматизированный процесс повторной настройки появился в версии Tarantool’а 1.10.2.

Запуск сервера с репликацией

Помимо процесса восстановления, описанного в разделе Процесс восстановления, сервер должен предпринять дополнительные шаги и меры предосторожности, если включена репликация.

И снова процедура запуска начинается с запроса box.cfg{}. Одним из параметров запроса box.cfg может быть replication, в котором указываются источники репликации. Реплику, которая запускается сейчас с помощью box.cfg, мы будем называть локальной, чтобы отличать ее от других реплик в наборе реплик, которые мы будем называть удаленными.

Если нет файла снимка .snap и не указано значение параметра `replication`:
то локальная реплика предполагает, что является нереплицируемым обособленным экземпляром или же первой репликой в новом наборе реплик. Она сгенерирует новые UUID для себя и для набора реплик. UUID реплики хранится в спейсе _cluster; UUID набора реплик хранится в спейсе _schema. Поскольку снимок содержит все данные во всех спейсах, это означает, что снимок локальной реплики будет содержать UUID реплики и UUID набора реплик. Таким образом, когда локальная реплика будет позднее перезапускаться, она сможет восстановить эти UUID после прочтения файла снимка .snap.

Если нет файла снимка .snap, указано значение параметра `replication`, а в спейсе `_cluster` отсутствуют UUID других реплик:
то локальная реплика предполагает, что не является обособленным экземпляром, но еще не входит в набор реплик. Сейчас она должна быть подключиться в набор реплик. Она отправит свой UUID реплики первой удаленной реплике, указанной в параметре replication, которая будет выступать в качестве мастера. Это называется «запрос на подключение». Когда удаленная реплика получает запрос на подключение, она отправляет в ответ:

  1. UUID набора реплик, в который входит удаленная реплика
  2. содержимое файла снимка .snap удаленной реплики.
    Когда локальная реплика получает эту информацию, она размещает UUID набора реплики в своем спейсе _schema, UUID удаленной реплики и информацию о подключении в своем спейсе _cluster, а затем создает снимок, который содержит все данные, отправленные удаленной репликой. Затем, если в WAL-файлах .xlog локальной реплики содержатся данные, они отправляются на удаленную реплику. Удаленная реплика получается данные и обновляет свою копию данных, а затем добавляет UUID локальной реплики в свой спейс _cluster.

Если нет файла снимка .snap, указано значение параметра `replication`, а в спейсе ``_cluster`` есть UUID других реплик:
то локальная реплика предполагает, что не является обособленным экземпляром, и уже входит в набор реплик. Она отправит свой UUID реплики и UUID набора реплик всем удаленным репликам, указанным в параметре replication. Это называется «подтверждение связи при подключении». Когда удаленная реплика получает подтверждение связи при подключении:

  1. удаленная реплика сопоставляет свою версию UUID набора реплик с UUID, переданным в ходе подтверждения связи при подключении. Если они не совпадают, связь не устанавливается, и локальная реплика отобразит ошибку.
  2. удаленная реплика ищет запись о подключающемся экземпляре в своем спейсе _cluster. Если такой записи нет, связь не устанавливается.
    Если есть, связь подтверждается. Удаленная реплика выполняет чтение любой новой информации из своих файлов .snap и .xlog и отправляет новые запросы на локальную реплику.

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

Если есть файл снимка и указан источник репликации:
сначала локальная реплика проходит процесс восстановления, описанный в предыдущем разделе, используя свои собственные файлы .snap и .xlog. Затем она отправляет запрос подписки всем репликам в наборе реплик. Запрос подписки содержит векторные часы сервера. Векторные часы включают набор пар „идентификатор сервера, LSN“ для каждой реплики в системном спейсе _cluster. Каждая удаленная реплика, получив запрос подписки, выполняет чтение запросов из файла .xlog и отправляет их на локальную реплику, если LSN из запроса файла .xlog больше, чем LSN векторных часов из запроса подписки. После того, как все реплики из набора реплик отправили ответ на запрос подписки локальной реплики, запуск реплики завершен.

Следующие временные ограничения применимы к версиям Tarantool’а ниже 1.7.7:

  • URI в параметре replication должны быть указаны в одинаковом порядке на всех репликах. Это необязательно, но помогает соблюдать консистентность.
  • Реплики в наборе реплик должны запускаться не одновременно. Это необязательно, но помогает избежать ситуации, когда все реплики ждут готовности друг друга.

Следующее ограничение всё еще применимо к текущей версии Tarantool’а:

  • Максимальное количество записей в спейсе _cluster32. Кортежи для устаревших реплик не переиспользуются автоматически, поэтому по достижении предела в 32 реплики, может понадобиться реорганизация спейса _cluster вручную.