502 wegen einer vollen Listen-Queue
PHP-FPM war nicht langsam. Docker-NAT auf Port 9000 warf SYNs, als der Backlog bei 128 endete.
nginx lieferte 502 in kurzen Wellen. Das PHP-FPM-Slowlog war leer. Die acht Worker waren beschäftigt, nicht fest. ss -ltn im php-Container zeigte Recv-Q bei 128 auf 9000/tcp. Neue Verbindungen bekamen ECONNREFUSED. Das ist ein Listen-Backlog, kein Application-Timeout.
Compose veröffentlichte 9000 über docker-proxy. Jeder nginx-Request öffnete eine neue TCP-Verbindung. net.core.somaxconn im php-Image war 128. listen.backlog im Pool wuchs nicht darüber. NAT addierte Latenz, die Queue füllte sich bei einem Katalog-Stampede, den Memcached später schluckte.
Das Problem war eine volle Accept-Queue auf docker-proxy, nicht langsames Laravel. Besucher sahen 502, während Worker gleich frei waren. Ich brauchte einen Unix-Socket, Keepalive und somaxconn passend zu listen.backlog.
Der Socket
nginx und php teilen ein Volume mit einem Unix-Socket. Upstream hat keepalive 16. docker-proxy liegt nicht auf dem Hot Path. somaxconn im php-Container ist 4096. listen.backlog passt dazu. pm.max_children blieb bei acht. Diese Zahl war nie die 502.
- error_log mit connect() failed meint weiter den Backlog, kein Fatal in Laravel.
- TCP 9000 bleibt für Host-PHP außerhalb von Compose. Die öffentliche Site nutzt es nicht.
- queue- und schedule-Container sprechen mit Redis, nicht mit diesem Socket.
Die 502er waren weg beim selben Traffic, der Recv-Q füllte. Die PHP-FPM-Zeit im Access-Log blieb. Geändert hat sich, wie viele Handshakes auf dem Boden warteten.
Was ich daraus mitnehme
Leeres Slowlog plus 502 ist ein Socket-Problem, bis das Gegenteil feststeht. Recv-Q am Listen-Limit ist der Beweis.
docker-proxy plus SYN pro Request ist eine Queue, die ein Stampede füllt. Unix-Socket und Keepalive nehmen sie vom Boden.
pm.max_children hochzusetzen hätte Recv-Q versteckt, bis der Host keinen RAM mehr hat. Das echte Limit war der Backlog.
