502(Bad Gateway)和504(Gateway Timeout)都来自同一层。请求先到nginx,nginx再转给后面的PHP-FPM或者别的后端服务,这一步没走通,nginx就把错误页返回给浏览器。看到这两个状态码,说明站点还活着、nginx也在跑,出问题的是它和上游之间那一段。反过来,如果浏览器直接报连接被重置、整个站点打不开,那问题在更前面,DNS、证书、防火墙、服务器本身,跟这两个状态码没关系。
先看连接和进程池
一句话区分:502是上游根本没接上话,504是接上了但等太久没等到回复。
502先看error.log,里面常见三种:connection refused,说明PHP-FPM没起来,或者socket路径跟nginx配置里写的对不上;no live upstreams,说明上游整个不可用;recv() failed,多半是进程被意外杀掉。如果是socket,用ls -l看一眼文件在不在、权限对不对,nginx和PHP-FPM跑在不同用户下时最容易出这个岔子。再看进程池,pm.max_children设得小,并发一上来子进程排满,新请求就没人接。用ps数一下fpm进程数量,跟配置的上限比一比,很快能看出来。
进程池不够有个明显特征:502集中在白天高峰,凌晨和深夜一切正常。
重启后恢复、过一阵又复发,说明根因没找到。子进程只涨不落,多半是代码里的数据库连接或者文件句柄没释放,也可能是某个插件在偷偷做全表扫描。这类盯进程的内存占用曲线就能看出来,一路往上走不见回落,就是泄漏。
上限不是越大越好,每个子进程都吃内存,max_children按可用内存除以单进程占用量估,再留一成给系统。调完重启PHP-FPM,别只重载nginx,配置是PHP那一侧的。
再看慢查询和慢日志
fastcgi_read_timeout默认60秒,上游超过这个时间没回应,nginx就判定超时。原因通常不在nginx:慢查询没走索引、代码里调第三方接口没设超时、导出大文件一口气查几十万行,都会让某个请求拖到几分钟。把超时调大只是把报错往后推,真实原因还得看PHP-FPM的slowlog,它会把超过阈值的调用栈打出来。慢查询拿explain看执行计划,重点看type是不是ALL、扫描行数是不是几十万;外部接口一律显式设超时,别依赖默认值。
治标的一招是给重页面加缓存。把首页、列表页、排行榜这类不常变的页面生成静态文件,或者放进对象缓存,请求不进PHP,上游压力立刻降一截。这一招不解决慢查询本身,但能让站点先稳住,腾出时间慢慢改代码。
两个方向的日志都在同一个文件里,nginx的error.log一行就能分辨:写着upstream timed out的是504,写着connection refused的是502。同一个时间点两个都出现,先处理502。
改完要复现验证。把当时那条请求重放一次,盯着error.log看是否还刷同样的行;线上再加一条5xx比率的监控,比等用户来投诉早几个小时知道。
申请创业报道,分享创业好点子。点击此处,共同探讨创业新机遇!
