Скачать CV
Назад к бизнес-кейсам

nginx

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.

Воркеры через секунду свободны. Accept-очередь уже полная.
Воркеры через секунду свободны. Accept-очередь уже полная.

Сокет

nginx и php делят том с unix-сокетом. У upstream keepalive 16. docker-proxy на горячем пути нет. somaxconn в контейнере php 4096. listen.backlog такой же. pm.max_children остался восемь. Это число 502 не было.

Unix-сокет на одном хосте. Keepalive на upstream. Без SYN на каждый HTML.
Unix-сокет на одном хосте. Keepalive на upstream. Без SYN на каждый HTML.
  • 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.

Назад к бизнес-кейсам