Суть инцидента
Произошел полный отказ трехузлового кластера PostgreSQL под управлением Patroni. Авария носила каскадный характер: падение мастера по причине исчерпания дискового пространства спровоцировало failover, после чего новый мастер также исчерпал место на диске из-за агрессивных настроек удержания WAL-файлов для отставшей реплики.
Хронология каскадного отказа
На основе логов восстановлена следующая цепочка событий:
- Смерть первого мастера: Нода 1 исчерпала свободное место на диске и аварийно остановилась. Перед падением она не успела отправить на реплики WAL-файл 000000070000013300000087.
- Отработка Failover: Patroni переключил роль лидера на Ноду 2.
- Блокировка репликации: Нода 3 запросила у нового мастера (Ноды 2) недостающий WAL-файл, но передать его было невозможно.
- Удушение нового мастера: Из-за наличия активного слота репликации и настройки max_slot_wal_keep_size = -1 (неограниченное хранение WAL), Нода 2 начала бесконечно копить новые WAL-файлы, пытаясь сохранить их для отстающей Ноды 3.
- Смерть второго мастера: Диск на Ноде 2 переполнился скопившимися WAL-файлами, и она также упала.
- Распад кластера: Нода 3 не могла стать мастером (потерян кворум etcd, т.к. они находились на тех же хостах). Кластер полностью остановил работу.
Как восстанавливали
- Работоспособность Ноды 2 была восстановлена путем расширения места на диске.
- Нода 1 была реинициализирована.
- Нода 3 так и не смогла получить запрошенный WAL …87, из-за чего была также выполнена её полная реинициализация.
Анализ причин инцидента
Авария стала возможной из-за комбинации отсутствующего мониторинга и фатальных ошибок в конфигурации PostgreSQL:
- max_slot_wal_keep_size = -1 — критическая ошибка. При такой настройке мастер никогда не удаляет WAL-файлы, если отставшая реплика их не подтвердила. Мастер жертвует собой (своим диском) ради реплики.
- checkpoint_timeout = 30 — экстремально низкое значение (30 секунд вместо дефолтных 5 минут). Это заставляет базу непрерывно сбрасывать данные на диск, генерируя гигантский объем WAL-трафика, что моментально забивает дисковое пространство.
- Отсутствие мониторинга свободного места и задержки репликации (lag) привело к тому, что проблема развивалась несколько часов, но была замечена только при полном разрушении кластера.
- Нахождение БД etcd на тех же хостах что и PostgreSQL. Когда на ноде 1, а затем и на ноде 2 закончилось свободное дисковое пространство из-за накопления WAL-файлов базы данных, служба etcd на этих серверах также потеряла возможность осуществлять запись.
План по предотвращению подобных сбоев
Конфигурация PostgreSQL
- Установить max_slot_wal_keep_size = 16GB (или иное разумное значение в зависимости от диска). Мастер должен отбрасывать безнадежно отставшую реплику, чтобы выжить самому.
- Вернуть checkpoint_timeout к значению по умолчанию 300 (5 минут) или выше, чтобы снизить генерацию WAL.
Архитектура и дисковая подсистема
- Вынести логи из PGDATA: Директория с логами PostgreSQL должна находиться вне каталога данных. Это спасет логи от удаления при выполнении реинициализации ноды.
- Разнести ОС и данные PostgreSQL на разные физические или логические диски.
- Унифицировать размер дисков на всех узлах кластера.
- Вынести кластер etcd на отдельные хосты.
Работа с логами и мониторинг
- Внедрить систему мониторинга (например, Zabbix) с обязательными алертами на: свободное место на дисках, статус репликации и отставание слотов.
- Настроить ротацию логов PostgreSQL с глубиной хранения не менее 2 недель.
- Настроить ротацию системного лога messages (logrotate). Сейчас файлы весят более 6 ГБ, что делает их оперативный анализ затруднительным.
Роль PGLens и Zabbix
В данном инциденте критически важно использовать комплексный подход: инфраструктурный мониторинг (Zabbix) для своевременного оповещения и глубокую аналитику профиля нагрузки (PGLens) для поиска первопричины. Совместная работа этих инструментов могла бы помочь на трех ключевых этапах.
1. Раннее выявление аномальной генерации WAL
- Роль Zabbix: Система зафиксировала бы резкое сокращение свободного места на дисках и отправила экстренное уведомление инженерам.
- Роль PGLens: Получив сигнал, администратор смог бы быстро найти причину аномалии. Инструмент непрерывно собирает статистику фоновых процессов, и на его графиках был бы отчетливо виден всплеск записи и зашкаливающее количество контрольных точек
2. Контроль «бесконечного» слота репликации
- Роль Zabbix: Настроеные триггеры просигнализировали бы об опасном отставании третьего узла от мастера.
- Роль PGLens: PGLens позволяет детально контролировать поток WAL и отслеживать состояние слотов репликации в реальном времени.
3. Независимый «черный ящик» при расследовании
При полном отказе кластера и потере данных Zabbix лишь констатирует факт недоступности серверов. Так как PGLens обычно хранит собранную статистику в отдельной независимой базе данных, все исторические метрики производительности сохранились бы даже после полного уничтожения каталога PGDATA на упавших узлах (при выполнении реинициализации). Это позволило бы с точностью до минуты восстановить картину нагрузки и состояние первого узла перед его аварийной остановкой, чтобы провести качественный разбор сбоя.