Поддержка сторожевого таймера
Запуск нескольких серверов PostgreSQL в качестве первичных может привести к потере транзакций из-за расхождения временных шкал. Такая ситуация также называется проблемой split-brain. Чтобы избежать split-brain, Patroni должен обеспечить, чтобы PostgreSQL не принимал фиксацию никаких транзакций после истечения срока действия ключа лидера в DCS. В нормальных условиях Patroni пытается достичь этого, останавливая PostgreSQL при неудаче обновления блокировки лидера по любой причине. Однако это может не произойти по различным причинам:
- Patroni аварийно завершил работу из-за ошибки, нехватки памяти или был случайно завершён системным администратором.
- Остановка PostgreSQL происходит слишком медленно.
- Patroni не получает процессорного времени из-за высокой нагрузки на систему, приостановки виртуальной машины гипервизором или других проблем инфраструктуры.
Чтобы гарантировать корректное поведение в этих условиях, Patroni поддерживает сторожевые таймеры. Сторожевые таймеры — это программные или аппаратные механизмы, которые перезагружают всю систему, если в течение заданного промежутка времени не получают сигнал keepalive. Это добавляет дополнительный уровень отказоустойчивости в случае, если обычные механизмы защиты Patroni от split-brain не сработают.
Patroni попытается активировать сторожевой таймер перед повышением PostgreSQL до первичного сервера. Если активация сторожевого таймера не удалась, а режим сторожевого таймера — required, узел откажется стать лидером. При решении участвовать в выборе лидера Patroni также проверит, позволит ли конфигурация сторожевого таймера вообще стать лидером. После понижения PostgreSQL (например, из-за ручного переключения при отказе) Patroni снова отключит сторожевой таймер. Сторожевой таймер также будет отключён, пока Patroni находится в режиме паузы.
По умолчанию Patroni настраивает сторожевой таймер так, чтобы он истек на 5 секунд раньше, чем истекает TTL. При настройке по умолчанию loop_wait=10 и ttl=30 это даёт HA-циклу не менее 15 секунд (ttl - safety_margin - loop_wait) на завершение до принудительного перезапуска системы. По умолчанию время ожидания доступа к DCS настраивается на 10 секунд. Это означает, что при недоступности DCS, например из-за сетевых проблем, у Patroni и PostgreSQL будет не менее 5 секунд (ttl - safety_margin - loop_wait - retry_timeout) для перехода в состояние, при котором все соединения клиентов будут завершены.
Запас безопасности — это время, которое Patroni выделяет между обновлением ключа лидера и отправкой сигнала keepalive сторожевому таймеру. Patroni попытается отправить keepalive немедленно после подтверждения обновления ключа лидера. Если процесс Patroni будет приостановлен на длительное время в критический момент, keepalive может быть задержан более чем на запас безопасности без срабатывания сторожевого таймера. Это создаёт окно времени, в течение которого сторожевой таймер не сработает до истечения срока действия ключа лидера, что нарушает гарантию. Чтобы абсолютно гарантировать срабатывание сторожевого таймера в любых условиях, настройте сторожевой таймер на истечение через половину TTL, установив safety_margin в -1, чтобы установить тайм-аут сторожевого таймера на ttl // 2. Если вам нужна такая гарантия, вероятно, следует увеличить ttl и/или уменьшить loop_wait и retry_timeout.
В настоящее время сторожевые таймеры поддерживаются только через интерфейс устройства сторожевого таймера Linux.
Настройка программного сторожевого таймера в Linux
По умолчанию конфигурация Patroni попытается использовать /dev/watchdog в Linux, если он доступен для Patroni. Для большинства сценариев использования программный сторожевой таймер, встроенный в ядро Linux, является достаточно безопасным.
Чтобы включить программный сторожевой таймер, выполните следующие команды от имени root перед запуском Patroni:
Для тестирования может быть полезно отключить перезагрузку, добавив soft_noboot=1 в строку команды modprobe. В этом случае сторожевой таймер будет просто записывать строку в кольцевой буфер ядра, доступный через dmesg.
Patroni будет записывать информацию о сторожевом таймере при его успешном включении.