PostgreSQL: долгий запуск и таймаут восстановления
После аварийного завершения PostgreSQL проигрывает журнал транзакций, и это занимает минуты. Если таймаут запуска в unit-файле меньше, systemd обрывает восстановление — и следующая попытка начинается заново, занимая ещё больше времени.
Что это значит
Признак именно этого случая: в журнале кластера видно «database system was not properly shut down; automatic recovery in progress», а затем сообщение systemd о таймауте. Прерывать такое восстановление вредно: работа теряется и начинается с начала.
Вероятные причины
По порядку: сверху то, что встречается чаще.
-
Таймаут запуска меньше времени восстановления
Восстановление зависит от объёма незаписанных изменений. На нагруженной базе это минуты, а значение по умолчанию часто меньше.
-
Каждая попытка прерывается, и восстановление не завершается никогда
При
Restart=alwaysи коротком таймауте получается цикл: восстановление начинается, обрывается и начинается снова. -
Медленный диск усугубляет восстановление
Проигрывание журнала — это интенсивная запись. На перегруженном или медленном диске оно затягивается.
Диагностика
Команды идут в том порядке, в котором их стоит выполнять: каждая следующая проверяет то, что осталось после предыдущей.
Записи о восстановлении и его прогрессе.
sudo tail -50 /var/log/postgresql/postgresql-16-main.logТаймаут и число прерванных попыток.
systemctl show postgresql@16-main -p TimeoutStartSec -p NRestartsРешение
Решение своё для каждой причины. Сначала определите, какая из них ваша, — иначе правки наложатся друг на друга.
- Почему происходит
- Восстановление зависит от объёма незаписанных изменений. На нагруженной базе это минуты, а значение по умолчанию часто меньше.
- Как проверить
-
Посмотрите таймаут и записи о восстановлении.
systemctl show postgresql@16-main -p TimeoutStartSec sudo grep -i "recovery" /var/log/postgresql/postgresql-16-main.log | tail -5
- Как исправить
-
Увеличьте таймаут в переопределении unit экземпляра. Для крупных баз разумны десятки минут.
sudo systemctl edit postgresql@16-main.service # [Service]\nTimeoutStartSec=30min
- Почему происходит
- При
Restart=alwaysи коротком таймауте получается цикл: восстановление начинается, обрывается и начинается снова.
- Как проверить
-
Посмотрите счётчик перезапусков и историю.
systemctl show postgresql@16-main -p NRestarts journalctl -u postgresql@16-main --no-pager | tail -30
- Как исправить
- Остановите службу, дождитесь завершения восстановления вручную через pg_ctl, затем запускайте через systemd с увеличенным таймаутом.
- Почему происходит
- Проигрывание журнала — это интенсивная запись. На перегруженном или медленном диске оно затягивается.
- Как проверить
-
Посмотрите нагрузку на диск во время запуска.
iostat -x 2 3 2>/dev/null || vmstat 2 3
- Как исправить
- Дождитесь завершения. На будущее — следите за корректной остановкой базы: аварийные завершения и есть источник этой проблемы.
Пример вывода
Восстановление прервано по таймауту. Пример показательный: он собран на тестовой машине специально для этой страницы, а не взят из чужого журнала.
postgres[6100]: LOG: database system was not properly shut down; automatic recovery in progress
postgres[6100]: LOG: redo starts at 0/16000028
systemd[1]: postgresql@16-main.service: start operation timed out. Terminating.
systemd[1]: postgresql@16-main.service: Failed with result 'timeout'.
Связанные ошибки
- Failed with result 'timeout' Состояние timeout: служба не уложилась в отведённое время при запуске, остановке или перезагрузке настроек.
- Job for … failed because a timeout was exceeded Задание на запуск прервано по таймауту. Как отличить медленный старт от заблокированного и правильно настроить TimeoutStartSec.
- PostgreSQL: data directory has invalid permissions Кластер PostgreSQL не запускается из-за прав на каталог данных. Требование 0700 или 0750 и как вернуть владельца.
- A start job is running: загрузка висит на одной службе Загрузка останавливается с обратным отсчётом: служба не укладывается в таймаут. Как найти виновника и не ждать.
- A stop job is running: выключение висит Перезагрузка останавливается с обратным отсчётом: служба не завершается. Как найти и сократить ожидание.
- Connection timed out в журнале службы Соединение не устанавливается по таймауту: пакеты отбрасываются, узел недоступен, перегружен сервер на другой стороне.
- Gunicorn: WORKER TIMEOUT в журнале службы Рабочие процессы Gunicorn убиваются по таймауту: медленные запросы, блокирующие вызовы, неверный тип обработчика.
- PostgreSQL: could not bind IPv4 address Кластер PostgreSQL не занимает порт: адрес занят другим экземпляром или остался файл сокета. Разбор.
Где встречается чаще всего
Источники
- Документация PostgreSQL: восстановление после сбоя
-
systemd.service(5)
TimeoutStartSec= и поведение при истечении. -
Воспроизведено на тестовой машине, systemd 255 (Ubuntu 24.04)
Воспроизведено аварийной остановкой нагруженного кластера с TimeoutStartSec=30s.