Перейти к основному содержимому

Режим отказоустойчивости DCS

примечание

Эта страница переведена при помощи нейросети GigaChat.

Проблема

Patroni в значительной степени полагается на распределенное хранилище конфигураций (DCS) для решения задачи выборов лидера и обнаружения разделения сети. То есть узлу разрешено запускать Postgres в качестве первичного только в том случае, если он может обновить блокировку лидера в DCS. В случае, если обновление блокировки лидера не удалось, Postgres немедленно понижается и запускается в режиме только для чтения. В зависимости от используемого DCS вероятность возникновения «проблемы» различается. Например, при использовании etcd, который применяется только для Patroni, вероятность близка к нулю, тогда как с K8s API (на базе etcd) это может наблюдаться чаще.

Причины текущей реализации

Сбой обновления блокировки лидера может быть вызван двумя основными причинами:

  1. Разделение сети;
  2. Недоступность DCS.

В общем случае невозможно различить эти две ситуации с точки зрения одного узла, и поэтому Patroni предполагает наихудший случай — разделение сети. В случае разделения сети другие узлы кластера Patroni могут успешно захватить блокировку лидера и повысить Postgres до первичного. Чтобы избежать ситуации split-brain, старый первичный узел понижается до истечения срока действия блокировки лидера.

Режим отказоустойчивости DCS

Введена новую специальную опцию — failsafe_mode. Она может быть включена только через глобальную динамическую конфигурацию, хранящуюся в ключе DCS /config. Если режим отказоустойчивости включен и обновление блокировки лидера в DCS не удалось по причинам, отличным от несоответствия версии/значения/индекса, Postgres может продолжать работать как первичный, если он может получить доступ ко всем известным участникам кластера через REST API Patroni.

Детали низкоуровневой реализации

  • Введен новый постоянный ключ в DCS с именем /failsafe.
  • Ключ /failsafe содержит всех известных участников данного кластера Patroni в данный момент времени.
  • Текущий лидер поддерживает актуальность ключа /failsafe.
  • Участнику разрешено участвовать в выборах лидера и стать новым лидером только в том случае, если он присутствует в ключе /failsafe.
  • Если кластер состоит из одного узла, ключ /failsafe будет содержать одного участника.
  • В случае «сбоя» DCS существующий первичный узел подключается ко всем участникам, представленным в ключе /failsafe, через REST API POST /failsafe и может продолжать работать как первичный, если все реплики подтвердят это.
  • Если один из участников не отвечает, первичный узел понижается.
  • Реплики используют входящие запросы REST API POST /failsafe как индикатор того, что первичный узел все еще активен. Эта информация кэшируется на ttl секунд.

Часто задаваемые вопросы

  • Почему текущий первичный узел ОБЯЗАН видеть ВСЕ остальные участники? Возможно ли полагаться на кворум здесь?

    Это отличный вопрос! Проблема в том, что представление о кворуме может различаться с точки зрения DCS и Patroni. В то время как узлы DCS должны быть равномерно распределены по зонам доступности, для Patroni такого правила нет, и что еще важнее, нет механизма для введения и обеспечения соблюдения такого правила. Если большинство узлов Patroni окажется в проигравшей части разделенной сети (включая первичный), а узлы меньшинства — в выигравшей части, первичный узел должен быть понижен. Только проверка ВСЕХ остальных участников позволяет обнаружить такую ситуацию.

  • Что произойдет, если узел/pod будет завершен, пока DCS недоступен?

    Если DCS недоступен, проверка «доступны ли ВСЕ остальные участники кластера?» выполняется каждый цикл цикла heartbeat (каждые loop_wait секунд). Если pod/узел завершен, проверка не пройдет, и Postgres будет понижен до режима только для чтения и не восстановится, пока DCS не будет восстановлен.

  • Что произойдет, если все участники кластера Patroni будут потеряны, пока DCS недоступен?

    Patroni можно настроить на создание новой реплики из резервной копии даже тогда, когда в кластере нет лидера. Но если новый участник отсутствует в ключе /failsafe, он не сможет захватить блокировку лидера и стать первичным.

  • Что произойдет, если первичный узел потеряет доступ к DCS, а реплики — нет?

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

  • Как включить режим отказоустойчивости?

    Перед включением failsafe_mode убедитесь, что версия Patroni на всех участниках актуальна. После этого можно использовать либо REST API PATCH /config, либо patronictl edit-config -s failsafe_mode=true.