先看现象。2 核 4G 的机器上 nginx 和 PHP-FPM 混部,某天并发升高后 ps 里的 worker 从四个变成三个,error.log 什么都没有,业务侧却出现一批连接被重置。
排查方向其实有限,先把可能性排一排。系统整体内存不足,内核挑占用较大的进程杀掉,nginx 的 worker 首当其冲。另一种情况是worker 的 oom_score_adj 是零,比数据库这类进程更容易被选中。
还有一种情况,大响应体配上大缓冲区,单个 worker 的常驻内存被撑得很高。
另外,worker 被杀之后 master 会重新拉起,但连接已经断了,日志里看不到完整现场。
动手时先在内核日志里确认击杀记录
dmesg -T | grep -i 'killed process' | tail -5
随后看各个 worker 的内存分布
ps -o pid,rss,cmd -C nginx --sort=rss
接着确认当前的 oom_score_adj
cat /proc/$(pidof nginx | awk '{print $1}')/oom_score_adj
剩下的就是把 nginx 调成不容易被杀
echo -500 > /proc/$(pidof nginx | awk '{print $1}')/oom_score_adj
恢复的判定其实很直接。压测期间 worker 数量不再减少,dmesg 里没有新的 killed process,业务侧连接重置的计数归零。
把 oom_score_adj 调低只是让别人先死,真正要解决的是混部导致的内存超卖,该拆机器就拆。报错文案容易误导,真正的原因往往在相邻那一层的日志里。
