Настройка восстановления после отказа в режиме stateful с etcd | Tdb
Руководство администратора Автоматическое восстановление после отказа Настройка восстановления после отказа в режиме stateful с etcd

Настройка восстановления после отказа в режиме stateful с etcd

Подробная информация об отказоустойчивой архитектуре приведена в документации Tarantool.

Схема переключения лидер-узлов

За смену экземпляров с ролью лидера в кластере отвечает узел-координатор. Переключение выполняется так:

  1. Один узел-координатор с ролью failover-coordinator захватывает на время блокировку в etcd. Так он становится активным, а остальные узлы с этой ролью – резервными.

  2. Координатор читает карту лидеров из etcd – информацию о том, какой узел является лидером в каждом из наборов реплик. При необходимости координатор меняет карту и обнуляет vclockkeeper (информацию о предыдущем лидере) для выбранных наборов реплик.

  3. Экземпляры хранилищ получают изменения в карте из etcd c помощью методов длинных опросов (запрос long‑poll на /leaders) и при наличии изменений выполняют переключение режима read_only.

Параметры, влияющие на скорость переключения лидера

Параметр

Описание

Значение по умолчанию

Где настраивать

lock_delay

Время действия (TTL) блокировки в секундах. Пока блокировка активна, решения принимает удерживающий ее координатор

10 с

Веб-интерфейс Cartridge → вкладка Failover / graphql-api / lua-api

LONGPOLL_TIMEOUT

Время ожидания long-poll-запроса в секундах на обновление топологии (GET /leaders)

30 с

require('cartridge.failover').set_options{ LONGPOLL_TIMEOUT = }

NETBOX_CALL_TIMEOUT

Время ожидания выполнения HTTP-запроса координатора к etcd

1 с

Для failover-клиента: cartridge.failover.set_options{ netbox_call_timeout = }
Для роли failover-coordinator: vars = require('cartridge.vars').new('cartridge.roles.coordinator'); vars.options.NETBOX_CALL_TIMEOUT =

RECONNECT_PERIOD

Время в секундах для повторного соединения с etcd

5 с

vars = require('cartridge.vars').new('cartridge.roles.coordinator'); vars.options.RECONNECT_PERIOD =

IMMUNITY_TIMEOUT

Минимальное время в секундах между переназначениями лидера

15 с

vars = require('cartridge.vars').new('cartridge.roles.coordinator'); vars.options.IMMUNITY_TIMEOUT =

WAITLSN_TIMEOUT

Время ожидания выравнивания LSN (в секундах) при переключении лидера, когда оба экземпляра рабочие (switchover)

3 с

require('cartridge.failover').set_options{ WAITLSN_TIMEOUT = }

failover_timeout

Время в секундах до перевода координатором лидера в статус dead и запуска восстановления после отказа

30 с (рекомендация)

Веб-интерфейс Cartridge → вкладка Failover / graphql-api / lua-api

fencing_pause

Интервал в секундах между проверками здоровья fencing_healthcheck(). Успешная проверка сбрасывает таймер

2 с

Веб-интерфейс Cartridge → вкладка Failover / graphql-api / lua-api

fencing_timeout

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

10 с

Веб-интерфейс Cartridge → вкладка Failover / graphql-api / lua-api

ROLES_APPLY_TIME

Время необходимое для применения ролей на экземпляре

нет

Нельзя настроить.

ETCD_DELAY

Время недоступности etcd (восстановление после сбоя, сетевой разрыв).

нет

Нельзя настроить.

Примечание

Рекомендованное соотношение настроек:

failover_timeout >> fencing_timeout > fencing_pause

При этом failover_timeout должен существенно превышать максимальную сетевую задержку между любыми двумя узлами кластера Tarantool, а также между координатором и etcd. В противном случае возможны ложные переключения лидера.

Возможные задержки при переключении

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

Задержка измеряется в величине RTT. Здесь время приема-передачи (RTT, round‑trip time) – это время, за которое HTTP‑запрос проходит полный цикл из Tarantool в etcd и обратно. Время приема-передачи включает: отправку HTTP‑запроса из Tarantool в etcd, обработку запроса в etcd, сетевую задержку и получение ответа из etcd.

Координатор

Состояние

Формула

Пояснение

Блокировка (/lock) уже удерживается

(2R + 1) × RTT

Суммарное время выполнения запросов на получение информации о текущем рабочем лидере (с которого нужно переключиться) и на запись информации о новом лидере (запросы GET /vclockkeeper и PUT /vclockkeeper) составляет 2 RTT, это значение нужно умножить на количество изменяемых наборов реплик R. Время выполнения запроса на изменение карты лидеров (PUT /leaders) составляет 1 RTT.

Блокировка (/lock) ещё не захвачена

(N + 3 + 2R) × RTT

Суммарное время выполнения запросов на захват блокировки (PUT /lock), а также на получение и изменение карты лидеров (GET /leaders и PUT /leaders) составляет 3 RTT. Суммарное время выполнения запросов GET /vclockkeeper и PUT /vclockkeeper составляет 2 RTT, это значение нужно умножить на количество изменяемых наборов реплик R.

Здесь:

  • R – количество наборов реплик, для которых меняется лидер;

  • N – количество endpoint’ов etcd, к которым пришлось обратиться, пока не получен ответ.

Переключение лидера вручную

При вызове метода failover.set_leaders() координатор уже удерживает блокировку, поэтому он отправляет только запрос на изменение в карте лидеров (PUT /leaders). Задержка здесь составляет 1 RTT.

Обнуление vclockkeeper в этом пути не выполняется: новую метку сохранит избранный лидер после применения конфигурации.

Узнать больше о продвижении лидера вручную можно в документации Tarantool.

Экземпляр Tarantool

Суммарная задержка, возникающая на экземпляре Tarantool, складывается из следующих составляющих:

  • получение изменений в карте лидеров из etcd (запрос GET /leaders) – 1 RTT;

  • получение информации о текущем рабочем лидере, с которого нужно переключиться (запрос GET /vclockkeeper) – 1 RTT;

  • получение информации о текущем рабочем лидере, с которого нужно переключиться, и запись информации о новом лидере (запросы GET /vclockkeeper и PUT /vclockkeeper) – 2 RTT.

Итоговая задержка:

4 RTT + ROLES_APPLY_TIME

Здесь:

  • ROLES_APPLY_TIME – время на применение ролей, значение этой переменной зависит от приложения.

Кроме того, при ручном переключении лидера (switchover) нужно дождаться выравнивания LSN (WAITLSN_TIMEOUT).

Итоговые оценки

Сценарий

Время (RTT + доп. задержки)

Ручное переключение лидера (блокировка уже захвачена)

((5 + 2R) × RTT) + WAITLSN_TIMEOUT + ROLES_APPLY_TIME

Падение лидера, координатор рабочий

((5 + 2R) × RTT) + failover_timeout + ROLES_APPLY_TIME

Падение лидера и активного координатора, etcd доступен

((5 + 2R) × RTT) + failover_timeout + ROLES_APPLY_TIME + lock_delay

Падение лидера и активного координатора, etcd недоступен

((5 + 2R) × RTT) + failover_timeout + ROLES_APPLY_TIME + lock_delay + ETCD_DELAY

Дополнительно возможны задержки событийного цикла Tarantool: плотный пользовательский Lua‑код может отложить обработку long‑poll, применение конфигурации и работу координатора.

Для встроенных ролей Cartridge значение ROLES_APPLY_TIME невелико, и им можно пренебречь.

Допустимое время обнаружения отказа лидера

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

Чтобы определить приемлемое время обнаружения отказа лидер-узла, сначала нужно опираться на требования к доступности системы: SLA (Service Level Agreement) и связанные показатели RTO (Recovery Time Objective).

SLA определяет допустимое время простоя за определенный период – например, процент доступности в виде количества «девяток». Чем строже требования SLA (больше «девяток» доступности), тем меньше суммарный простой системы в месяц или год:

Доступность, %

Время простоя в год

Время простоя в месяц

90% — «одна девятка»

876 ч

72 ч

95%

438 ч

36 ч

98%

175,2 ч

14,4 ч

99% — «две девятки»

87,6 ч

7,20 ч

99.5%

43,92 ч

3,60 ч

99.8%

17,52 ч

86,23 мин

99,9% — «три девятки»

8,76 ч

43,2 мин

99.95%

4,38 ч

21,56 мин

99,99% — «четыре девятки»

52,56 мин

4,32 мин

99,999% — «пять девяток»

5,26 мин

25,9 сек

99,9999% — «шесть девяток»

31,5 сек

2,59 сек

В свою очередь, RTO – это максимальное время восстановления системы после сбоя, приемлемое для бизнеса. RTO определяет, сколько времени сервис может быть недоступен при отказе, прежде чем это нарушит SLA или требования бизнеса.

Принято, что время обнаружения отказа лидера (failover_timeout) и время переключения на резервный узел вместе должны укладываться в заданный RTO. Если ваш SLA определяет, что при сбое сервис должен восстановиться, например, не более чем за 1 минуту (RTO = 60 секунд), то время на обнаружение сбоя лидера должно быть существенно меньше этого значения, чтобы осталось время на сам процесс переключения. Формально это можно выразить так:

(failover_timeout + T_failover) ≤ RTO,

где T_failover – время, необходимое для фактического выполнения переключения на резервный экземпляр, в том числе перевод реплики в статус лидера, перенаправление запросов и запуск сервисов на новом лидере.

Таким образом, допустимое время обнаружения отказа failover_timeout можно оценить так:

failover_timeout ≈ RTO – T_failover.

Например, если RTO составляет 60 с, а переключение на реплику занимает около 30 с, то значение failover_timeout должно быть около 30 с или меньше. Если же бизнес требует RTO в считанные секунды, то и обнаружение отказа должно происходить за секунды – что на практике очень сложно и дорого обеспечить.

Таким образом, расчёт времени обнаружения отказа лидера проводится так:

  1. Определите требования к максимуму простоя (SLA). Узнайте, какой процент доступности или максимальный простой допускаются.

  2. Установите RTO на основе бизнес-требований. RTO обычно формулируется как допустимое время восстановления при единичном инциденте. Он должен соответствовать SLA, например, для 99.99% может потребоваться RTO около 1–2 минут или меньше. Если SLA выражен только в процентах, можно перевести его в допустимый простой и распределить на ожидаемое число отказов. Например, если максимум простоя в месяц составляет 4 минуты, и вы хотите покрыть 2 сбоя в месяц, то цель – не более 2 минут на восстановление каждого, включая обнаружение.

  3. Рассчитайте необходимое время обнаружения отказа лидера (failover_timeout). Рекомендованная нижняя граница для этого времени – 1 секунда. Tarantool работает в среде без строгих гарантий реального времени – задержки могут вносить событийный цикл (event loop) и планировщик файберов Tarantool, а также сетевые стеки ОС. Например, минимальное время ожидания повторной отправки TCP SYN по умолчанию составляет ~1 с, что уже задаёт нижнюю границу обнаружения падения узла. Даже при очень маленьких настройках восстановления после отказа фундаментальные задержки сети и ОС обойти нельзя.

Рекомендованные значения настроек

  • fencing_pause ≈ 1–2 с;

  • fencing_timeout ≈ 5–6 × fencing_pause. Пример: 5–10 с при значении fencing_pause в 1–2 c;

  • failover_timeout ≈ 2.5–4 × fencing_timeout. Пример: 25–40 с при значении fencing_timeout в 10 с.

Такие рекомендованные значения:

  • дают рабочему лидеру около 10 секунд, чтобы уйти в состояние read_only, если он действительно отрезан;

  • откладывают переключение лидера примерно до 30 секунд, снижая риск ложного срабатывания failover;

  • увеличивают RTO на запись, но остаются в разумных пределах для большинства OLTP‑нагрузок.

Если максимальная сетевая задержка приближается к значению failover_timeout, возможны ложноположительные переключения. Координатор может принять такую задержку за «смерть» узла лидера. Механизм fencing переводит узел в состояние read_only и этим частично снижает риск ложноположительного переключения, однако окно гонки остаётся и при высокой RPS возможны конфликты репликации. Конфликт репликации гораздо хуже краткой недоступности в read_only. При таком конфликте одновременно теряется часть записей и отсутствует возможность писать данные, а восстановление занимает существенно больше времени и почти всегда требует привлечения дежурной команды DBA/SRE.

Важно

Подбирайте значения настроек для stateful failover с etcd, исходя из реальной сетевой задержки до etcd и цены простоя записи в вашем сервисе.

Почему fencing не гарантирует отсутствие split-brain

Split-brain – появление двух и более лидер-узлов в одном наборе реплик, которое может привести к конфликту репликации.

Режим выбора лидера fencing не гарантирует отсутствие split-brain в следующих ситуациях:

  • Частичное разделение сети. Лидер может потерять связь с etcd, но при этом видит минимум одну реплику и остается доступным для записи.

  • Задержки событийного цикла. Переход узла в состояние read_only выполняется в общем цикле; тяжёлый Lua-код может отложить переход.

Даже при корректно настроенных таймаутах остаётся риск короткого окна, когда два узла одновременно считают себя лидерами. Именно в этот момент может возникнуть split-brain.

Примечание

Описанные выше особенности работы исправлены в Tarantool DB версии 2.x. В Tarantool DB 2.x:

  • Координаторы – это отдельные экземпляры, на которых не исполняется клиентский код. Это означает, что работу координаторов ничего не будет тормозить.

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

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

Подробнее о работе координатора в Tarantool DB 2.x можно узнать в документации Tarantool DB 2.x.

Ключевые различия между Tarantool DB версий 1.x и 2.x, а также обновление Tarantool DB с 1.x до 2.x описаны в разделе Обновление Tarantool DB с версий 1.x до 2.x.

Нашли ответ на свой вопрос?
Обратная связь