Top.Mail.Ru
Синхронная репликация | Tarantool
 
Репликация / Синхронная репликация
Репликация / Синхронная репликация

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

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

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

Эту проблему решает синхронная репликация. Каждая синхронная транзакция проходит коммит лишь после репликации на некотором количестве экземпляров, и только тогда клиенту приходит ответ о завершении транзакции.

Начиная с версии Tarantool 2.5.1, синхронную репликацию можно включать для отдельных спейсов, используя параметр is_sync:

box.schema.create_space('test1', {is_sync = true})

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

Управлять поведением синхронных транзакций можно с помощью глобальных параметров box.cfg:

box.cfg{replication_synchro_quorum = <количество экземпляров>}

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

-- Экземпляр 1
box.cfg{
    listen = 3313,
    replication_synchro_quorum = 2,
}
box.schema.user.grant('guest', 'super')
_ = box.schema.space.create('sync', {is_sync=true})
_ = _:create_index('pk')
-- Экземпляр 2
box.cfg{
    listen = 3314,
    replication = 'localhost:3313'
}
-- Экземпляр 1
box.space.sync:replace{1}

Операция replace(), вызванная на первом экземпляре, не будет завершена, пока второй экземпляр не подтвердит получение и успешное применение транзакции. Обратите внимание, что кворум равен 2, а реплика одна, но транзакция все же успешно проходит коммит. Это происходит потому, что мастер также участвует в кворуме.

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

-- Экземпляр 2
Ctrl+D
-- Экземпляр 1
tarantool> box.space.sync:replace{2}
---
- error: Quorum collection for a synchronous transaction is timed out
...

Транзакция не прошла коммит, поскольку за определенное время не был набран кворум. Время — ещё один параметр конфигурации:

box.cfg{replication_synchro_timeout = <время в секундах; может иметь тип float>}

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

Успешные коммиты синхронных транзакций персистентно сохраняются в журнал упреждающей записи (WAL) в виде особых записей CONFIRM. Сообщения об отмене транзакций сохраняются аналогичным образом в виде записей ROLLBACK.

Параметры timeout и quorum на репликах не используются. Если мастер прекратит работу, синхронные транзакции, которые находятся в обработке на репликах, будут ожидать выборов нового мастера.

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

Если наряду с несколькими синхронными транзакциями, ожидающими репликации, совершается асинхронная транзакция, она блокируется синхронными. Коммиты при этом выполняются в той последовательности, в которой для каждой из транзакций вызывается метод box.commit(). Похожим образом работает обычная очередь асинхронных транзакций. Можно сформулировать правило коммитов: порядок коммитов соответствует порядку вызова box.commit() для каждой из транзакций, независимо от того, синхронные транзакции или асинхронные.

Если для одной из синхронных транзакций истечет время ожидания, эта транзакция будет отменена, а вместе с ней и все последующие транзакции в очереди на репликацию. Похожим образом отменяются и асинхронные транзакции при ошибке записи в WAL. Действует правило отмены: транзакции отменяются в порядке, обратном порядку вызова box.commit() для каждой из них, независимо от того, синхронные транзакции или асинхронные.

Асинхронная транзакция, заблокированная синхронной, не становится сама синхронной, а просто ожидает коммита синхронной транзакции. Как только это произойдет, асинхронная транзакция сразу сможет пройти коммит, не ожидая репликации.

До версии 2.5.2 способа настроить синхронную репликацию для существующих спейсов не было. Однако, начиная с версии 2.5.2, ее можно включить, вызвав метод space_object:alter({is_sync = true}).

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

Анонимные реплики принимают участие в кворуме. Однако в будущих версиях это изменится: для синхронной транзакции кворум с участием анонимных реплик собрать будет нельзя.

В Tarantool, начиная с версии 2.6.1, есть встроенная функциональность для управления автоматическими выборами лидера (automated leader election) в наборе реплик. Подробности можно найти в соответствующей главе.

Если транзакция была отменена, это не обязательно значит, что реплики получили сообщение ROLLBACK. Может возникнуть ситуация, когда мастер внезапно прекратит работу, а после этого коммит транзакции будет выполнен новым мастером. Учитывайте это в логике вашего приложения.

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