Nginx отдаёт 502 с «connect() to unix:…php-fpm.sock failed (11: Resource temporarily unavailable)» под нагрузкой: утечка в воркерах и pm.max_requests

Что было. После перевода нагруженных сайтов на nginx + PHP-FPM начались 502. В error.log nginx: connect() to unix:/…/php-fpm.sock failed (11: Resource temporarily unavailable) while connecting to upstream. Поднимали pm.max_children с 5 до 1500, не помогло; при правках конфигурации служба зависала и требовала ручного перезапуска.

Что означает «Resource temporarily unavailable» на сокете. Очередь ожидающих соединений к сокету FPM (backlog) переполнена: все воркеры заняты, новые соединения не принимаются. Причин две: воркеров действительно мало для потока запросов, либо воркеры есть, но они медленные или «распухшие» и работают хуже с каждым часом.

Что нашёл автор. Режим pm = dynamic без ограничения числа запросов на воркер плюс утечка памяти в приложении: воркеры жили сутками, росли, система уходила в подкачку, отклик падал, очередь переполнялась. Добавление pm.max_requests = 1000 (воркер перезапускается после 1000 запросов) убрало 502. Подтверждено. Огромный max_children при этом только вредил: 1500 процессов PHP на одной машине это гарантированный OOM.

Как настраивать пул.

  1. Замерить память воркера (ps -ylC php-fpm8.3 --sort:rss) и посчитать pm.max_children от свободной памяти (об этом есть отдельный разбор).
  2. pm.max_requests = 500–1000: дешёвая защита от утечек в любом PHP-коде и расширениях.
  3. Очередь сокета: listen.backlog = 511 (или больше) в пуле и net.core.somaxconn = 1024 в sysctl: короткие пики переживаются без 502.
  4. request_terminate_timeout = 60s и request_slowlog_timeout = 5s + slowlog: медленные запросы видны и не держат воркеры бесконечно.
  5. Статус-страница пула (pm.status_path = /fpm-status, закрыть доступ снаружи) показывает listen queue, active processes, max children reached: по ней видно, чего не хватает.
  6. После правок php-fpm8.3 -t и systemctl reload php8.3-fpm; зависания при перезапуске в исходной истории были связаны с тем, что воркеры не завершались вовремя, process_control_timeout = 10s решает.

Как отличить от других 502.

  • (111: Connection refused): FPM не запущен или сокет с другим путём/правами.
  • (13: Permission denied): nginx не имеет прав на сокет (listen.owner/listen.group в пуле).
  • upstream timed out (110): воркер жив, но запрос дольше fastcgi_read_timeout.
  • (11: Resource temporarily unavailable): этот случай, очередь.

Параметры пула описаны в документации PHP.