排查Nginx搭配PHP
线上Nginx加PHP-FPM跑得好好的突然甩一堆502,多半是FastCGI这条通道上的毛病。要么进程池满新请求没坑位,要么慢耗时把连接耗干,又或者通信底层不稳。搞清楚服务器实际内存再定进程上限,别闭眼往大里调,配上合适的超时时间和慢日志,切到Unix So
跑着线上业务的机器突然蹦502,别第一反应就是业务代码翻车。这种报错十有八九是Nginx和PHP‑FPM之间那条链路绷了,翻来覆去就三类情况:请求超时被Nginx一刀切、PHP‑FPM那边子进程全占满没余量、底层通信抽风连不通。有些运维一撞上502就习惯性把参数全往大了调,结果内存先爆了,故障闹得更大。找准病根再动手,比盲目加配置踏实得多。
进程耗尽与超时机制的博弈
PHP‑FPM的子进程一旦被打满,新来的请求就只能搁在backlog队列里排着,排得久了超过Nginx这边的等待门槛,直接就甩502回来。定进程数有个很土却管用的办法:拿服务器预留出来给PHP的那部分内存,除以单个PHP进程的平均内存占用,算出来的数就是pm.max_children的安全线,千万别脑袋一热就往大了填。也别图省事抱着安装包自带的默认值不放,线上环境最好把pm.max_requests设到1000到5000这个区间,定期回收子进程,能躲开内存泄漏慢慢把服务磨死的那种暗坑。要是业务里确实有跑得比较长的脚本,一定要配上request_terminate_timeout,到了点就把超时请求硬断掉,让一条慢请求拖死整个进程池划不来。
Nginx这头也别死抱默认的60秒fastcgi_read_timeout不放,结合自己业务的峰值习惯,可以试着拉到300秒左右,再顺手调下fastcgi_send_timeout,遇到大文件上传或者长耗时接口的时候,通信就不容易卡住,能压住不少看起来莫名其妙的502。
通信方式和缓冲区配得好不好,效果差得还挺明显。同一台机器上部署的Nginx和PHP‑FPM,用Unix Socket比走TCP回环少了一层网络栈的开销,通信超时碰出502的概率会低一些,但得提前把Socket文件的权限配好,免得权限不足反而捅出新篓子。平时响应头要是体积偏大,也可以适当把Nginx的fastcgi缓冲区调大,别让缓冲区塞不下直接返回502。排查的时候别光在Nginx的错误日志里打转,把PHP‑FPM的慢日志、错误日志都打开,两边对照着捋,定位毛病能少绕不少弯路。