502 из-за полной listen-очереди
PHP-FPM не был медленным. Docker NAT на порт 9000 ронял SYN, когда backlog упирался в 128.
nginx короткими пачками отдавал 502. slowlog PHP-FPM был пустой. Восемь воркеров были заняты, не зависли. ss -ltn в контейнере php показывал Recv-Q на 128 у 9000/tcp. Новые соединения получали ECONNREFUSED. Это listen backlog, а не таймаут приложения.
Compose публиковал 9000 через docker-proxy. Каждый запрос nginx открывал новое TCP-соединение. net.core.somaxconn внутри образа php был 128. listen.backlog в пуле выше этого не рос. NAT добавлял задержку, очередь наполнялась на stampede каталога, который потом забрал Memcached.
Проблема была в полной accept-очереди на docker-proxy, не в медленном Laravel. Посетители видели 502, пока воркеры уже почти освобождались. Нужен unix-сокет, keepalive и somaxconn вровень с listen.backlog.
Сокет
nginx и php делят том с unix-сокетом. У upstream keepalive 16. docker-proxy на горячем пути нет. somaxconn в контейнере php 4096. listen.backlog такой же. pm.max_children остался восемь. Это число 502 не было.
- error_log с connect() failed по-прежнему про backlog, а не про fatal в Laravel.
- TCP 9000 остаётся для PHP на хосте вне Compose. Публичный сайт им не ходит.
- Контейнеры queue и schedule говорят с Redis, не с этим сокетом.
502 пропали на том же трафике, который раньше забивал Recv-Q. Время PHP-FPM в access-логе не изменилось. Изменилось число рукопожатий, которые ждали на полу.
Какой опыт из этого
Пустой slowlog плюс 502 это проблема сокета, пока не доказано иное. Recv-Q на лимите listen это доказательство.
docker-proxy и SYN на запрос это очередь, которую stampede заполнит. Unix-сокет и keepalive снимают её с пола.
Поднятие pm.max_children спрятало бы Recv-Q, пока на хосте не кончится RAM. Настоящий лимит был backlog.
