Падение PostgreSQL от OOM Killer: Причины и предотвращение краша СУБД
- Внезапная перезагрузка PostgreSQL с сообщением
LOG: server process (PID ...) was terminated by signal 9: Killed. - В
dmesgпоявляется записьOut of memory: Killed process postgres. - Все активные клиентские транзакции аварийно сбрасываются с переходом СУБД в режим восстановления из WAL (Crash Recovery).
1. Анализ логов аварийного завершения
dmesg -T | grep -Ei "oom[_-]killer|postgres"
journalctl -u postgresql -n 100 --no-pager2. Корректный расчет потребления памяти PostgreSQL
Суммарный пиковый объем выделяемой памяти рассчитывается по формуле:
Max Memory = shared_buffers + (max_connections * (work_mem + maintenance_work_mem + temp_buffers))Безопасные параметры для сервера с 32 ГБ RAM:
# /etc/postgresql/16/main/postgresql.conf
shared_buffers = 8GB # 25% от общей RAM
work_mem = 32MB # Ограничение памяти на одну операцию сортировки
maintenance_work_mem = 1GB # Память для VACUUM и CREATE INDEX
max_connections = 200 # Не завышайте без внешнего пулера pgBouncer3. Защита основного процесса postmaster от OOM Killer
Отредактируйте сервис Systemd (systemctl edit postgresql):
[Service]
# Принудительный иммунитет для родительского процесса
OOMScoreAdjust=-1000systemctl daemon-reload
systemctl restart postgresql4. Системные ограничения ядра Linux
В файле /etc/sysctl.d/99-postgresql.conf установите запрет оверкоммита:
vm.overcommit_memory = 2
vm.overcommit_ratio = 80sysctl --system Частые вопросы (FAQ)
Почему при убийстве одного дочернего процесса падает весь PostgreSQL?
Дочерний backend-процесс разделяет общую память (shared buffers) с другими процессами. При его внезапном уничтожении через SIGKILL ядро СУБД не может гарантировать целостность структур памяти и перезапускает все процессы кластера для безопасности.
Почему параметр work_mem не защищает от OOM при сложных запросах?
work_mem выделяется на каждую отдельную операцию сортировки, хэширования или соединения внутри одного SQL-запроса. Сложный запрос с несколькими JOIN и SORT может выделить work_mem десятки раз одновременно.
Как снизить риск OOM при высоком числе клиентов?
Используйте транзакционный пулер соединений (pgBouncer или Odyssey), уменьшив параметр max_connections в самом PostgreSQL до 100-200 соединений.
Как проверить текущий OOM Score процесса postmaster?
Выполните: cat /proc/$(pgrep -f 'postgres -D')/oom_score_adj. Должно возвращаться значение -1000.