先看现象。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 调低只是让别人先死,真正要解决的是混部导致的内存超卖,该拆机器就拆。报错文案容易误导,真正的原因往往在相邻那一层的日志里。

作者 9823189