Sentinel: автоматический failover для master-replica

Предпосылки: репликация (failover, кворум, split brain), распределённый консенсус (leader election, кворум, терм), репликация Redis, Sub.

Репликация | Cluster

Проблема: ручной failover

Репликация даёт копии данных, но при падении мастера кто-то должен: обнаружить сбой, выбрать реплику, промоутировать её в мастер, перенаправить остальные реплики и клиентов на новый адрес. Ночью это означает: алерт будит дежурного инженера, инженер заходит на сервер, проверяет состояние, вручную выполняет REPLICAOF NO ONE, меняет конфигурацию остальных реплик, обновляет адрес в приложении — минуты простоя и высокий риск ошибки под давлением. Redis Sentinel автоматизирует весь этот цикл.

Что такое Sentinel

Sentinel (англ. sentinel — «часовой», «дозорный») — отдельный процесс (redis-sentinel или redis-server --sentinel), который непрерывно наблюдает за master-replica топологией и координирует переключение мастера при сбое. Название отражает роль: процесс стоит «на посту», следит за здоровьем узлов и поднимает тревогу при обнаружении проблемы.

В production Sentinel запускают несколькими экземплярами — минимум 3, и Redis официально рекомендует нечётное число. Почему именно нечётное — объяснено в репликации: чётное число (например, 4) не увеличивает отказоустойчивость, а при разделении пополам ни одна сторона не набирает большинства и failover невозможен. Один Sentinel — единая точка отказа: если он недоступен, клиентам не у кого спросить «кто сейчас мастер», а автоматическое голосование не состоится.

Sentinel не обязан быть на отдельном сервере: его часто запускают на тех же машинах, что и Redis (например, по одному Sentinel на каждый узел master/replica). Важно другое: Sentinel’ы должны быть разнесены по разным зонам отказа (разные хосты/VM), чтобы падение одного сервера не «убило» большинство.

Обнаружение топологии

Чтобы реагировать на сбои, Sentinel должен знать, кто мастер, какие реплики существуют и какие ещё Sentinel’ы работают. Конфигурация при этом минимальна — достаточно указать мастер и порог согласия:

sentinel monitor mymaster 192.168.1.10 6379 2

Последний аргумент — quorum: сколько Sentinel’ов должны согласиться с недоступностью мастера, прежде чем он будет признан недоступным коллективно. Этот порог определяет чувствительность детекции; для авторизации самого failover действует второй, более строгий порог — majority.

Остальную топологию Sentinel обнаруживает сам. О репликах он узнаёт через INFO, которую периодически отправляет мастеру. О других Sentinel’ах — через Pub/Sub-канал __sentinel__:hello на мастере: каждый Sentinel публикует туда информацию о себе и получает аналогичные сообщения от соседей.

Обнаружение сбоя: SDOWN и ODOWN

Зная топологию, Sentinel может проверять доступность узлов. Каждый Sentinel периодически отправляет PING мастеру и репликам. Если мастер не отвечает в течение down-after-milliseconds (порог в конфигурации Sentinel), Sentinel помечает его как субъективно недоступный — SDOWN. «Субъективно» — потому что это мнение одного процесса: возможно, проблема не в мастере, а в сети между ним и этим конкретным Sentinel’ом.

Чтобы исключить ложные срабатывания, Sentinel, обнаруживший SDOWN, опрашивает остальных. Когда количество согласных с недоступностью достигает quorum (параметр из конфигурации), мастер переходит в статус объективно недоступного — ODOWN. Это уже коллективное решение, а не мнение одного наблюдателя. Если мастер снова начинает отвечать на PING, метки снимаются и failover не запускается.

Failover: от обнаружения до нового мастера

Два порога: quorum и majority

ODOWN означает, что несколько Sentinel’ов согласились с недоступностью мастера, но для запуска failover этого недостаточно. В Sentinel действуют два отдельных порога, и различие между ними определяет, как Sentinel защищается от split brain.

Первый порог — quorum (настраиваемый). Он определяет, сколько Sentinel’ов должны подтвердить недоступность мастера, чтобы перейти от SDOWN к ODOWN. Quorum можно установить относительно низким (например, 2 из 5) для быстрой детекции: чем меньше порог, тем быстрее система распознаёт сбой.

Второй порог — majority (фиксированный). Для авторизации failover требуется согласие строгого большинства всех настроенных Sentinel’ов (не только живых на данный момент), то есть больше половины. При пяти Sentinel’ах majority равен трём: если трое из пяти недоступны, оставшиеся двое не смогут провести failover, даже если оба видят мастер недоступным.

Зачем нужен именно majority, а не просто quorum? Допустим, сеть разделилась: в одном сегменте — мастер и три Sentinel’а, в другом — две реплики и два Sentinel’а. Если бы для failover хватало quorum = 2, меньшая группа промоутировала бы реплику при работающем мастере — два мастера одновременно, split brain. Majority исключает это: большинство может быть только одно, поэтому ровно одна группа Sentinel’ов способна авторизовать failover.

Выборы лидера среди Sentinel’ов

Получив авторизацию от majority, Sentinel’ы должны решить, кто из них будет выполнять failover. Sentinel, обнаруживший ODOWN первым, запрашивает голоса у остальных. Каждый Sentinel отдаёт голос ровно одному кандидату за эпоху failover (failover epoch — счётчик, инкрементируемый при каждой попытке). Первый запросивший получает голос. Чтобы Sentinel’ы не стартовали выборы одновременно, каждый добавляет случайную задержку (jitter) перед запросом голосов — аналогично тому, как рандомизированные таймауты в Raft разводят кандидатов по времени.

Sentinel, набравший большинство голосов, становится лидером и берёт на себя выполнение failover. Это заимствование из алгоритмов консенсуса: кворумное голосование, один голос за эпоху, лидер исполняет решение. Однако Sentinel не реализует полноценный консенсус: он не согласовывает состояние через replicated log, и в граничных случаях — одновременные failover’ы, нестабильный (flapping) мастер, то появляющийся, то исчезающий, сетевые разделения, заживающие в середине процесса — возможны гонки. Это приемлемый компромисс: Sentinel — HA-механизм для системы с асинхронной репликацией, а не CP-консенсус, и его задача — минимизировать downtime, а не гарантировать, что все клиенты в каждый момент видят одного и того же мастера.

Выбор реплики и промоутирование

Лидер определяет, какую реплику промоутировать. Sentinel сравнивает кандидатов по трём критериям в порядке убывания приоритета. Первый — значение replica-priority в redis.conf реплики (по умолчанию 100, меньше — приоритетнее). Оператор понижает его для реплик на мощном железе и выставляет 0 для реплик, выделенных под аналитику или бэкапы, — такие реплики никогда не становятся мастером. Второй критерий — replication offset: реплика с наибольшим offset потеряла меньше всего данных при асинхронной репликации. Третий — run ID (уникальный идентификатор, который Redis генерирует при каждом запуске): при равенстве предыдущих критериев выбирается реплика с лексикографически меньшим ID. Это чистый tiebreaker для детерминизма — на практике до него доходит редко.

Выбранная реплика получает команду REPLICAOF NO ONE и становится мастером. Остальные реплики перенаправляются на нового мастера. Если старый мастер вернулся после failover, Sentinel автоматически переконфигурирует его как реплику — ручное вмешательство не требуется.

Весь процесс — от падения мастера до завершения failover — занимает ощутимое время: down-after-milliseconds на детекцию, согласование ODOWN, голосование лидера, промоутирование реплики, перенаправление остальных. Sentinel — это не «нулевой downtime», а способ держать downtime в пределах настроенных таймаутов (типично — единицы–десятки секунд вместо минут ручного переключения).

Обнаружение мастера клиентом

Failover переключил серверную часть: реплика стала мастером, остальные реплики перенаправлены. Но клиент до сих пор подключён к старому адресу — ему тоже нужно узнать о смене мастера. Клиенты подключаются не напрямую к мастеру, а спрашивают у Sentinel, кто сейчас мастер:

# подключиться к любому Sentinel (обычно порт 26379) и спросить:
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster

Клиентские библиотеки (redis-py, jedis, ioredis, redis-rb) поддерживают режим Sentinel: клиент подключается к списку Sentinel’ов, получает адрес мастера и автоматически переподключается при failover. Для быстрого реагирования на смену мастера клиент может подписаться на Pub/Sub канал +switch-master — это канал самого Sentinel-процесса (не обычного Redis-сервера), в который Sentinel публикует событие при каждом failover.

Границы Sentinel

Sentinel решает задачу высокой доступности (HA): автоматическое обнаружение сбоя и failover. Но он не делит данные между узлами — все данные по-прежнему на каждом сервере. Для горизонтального масштабирования нужен Cluster.

Потеря данных при failover остаётся возможной — это следствие асинхронной репликации: команды, не дошедшие до реплик до момента падения мастера, теряются при промоутировании. Масштаб потери ограничен окном асинхронности, но для критичных операций стоит использовать WAIT и/или настройки кворума реплик на запись.

Sources


Репликация | Cluster