大量短时进程导致CPU负载过高案例
1、背景
某项目的开发环境,单台虚拟机装了1套 mongo 集群用于测试,1个 mongos + 3节点 config + 1shard * 3副本,总计7个 mongo 实例。mongo 版本 4.2.19 ,OS 为 centos 7.9 。
测试结束后 cpu 负载一直维持在 50% 左右,而此时 mongo 的 qps 已经下降为0。
这台机器上只安装了 mongo ,将所有 mongo 实例关闭,cpu 负载立即恢复正常,再将 mongo 实例开启,过了一会 cpu 负载又开始飙升。场景能复现,且确认是跟 mongo 实例有关系。
2、诊断
执行 top 命令,cpu 的 usr 已经达到了 40% ,但是前几个进程的 %cpu 加起来远远凑不够数。
查看 mongos 的 qps ,确实没有执行用户命令了。
dstat 查看整体负载(vmstat 格式化做的不好,最后几列总是对不齐整)。
除了 cpu 负载不正常,其余指标均正常,中断和上下文切换也不算高,不太可能是这两个引发的。perf record -ag -- sleep 10 && perf report 查看 cpu 执行情况。
确实有大量 mongo 调用,但是 API 命名不直观,无法猜测对应的执行逻辑。
至此,确认是 mongo 实例引发的问题,但是 mongo 的应用连接为0,看调用 API 栈也找不到有用信息。
回到本文开头,top 进程的cpu利用率加起来远远小于 cpu 总体负载,大概率是有频繁短时进程偷走了这部分 CPU 资源,导致top命令来不及捕获统计。
sar -w 1 查看每秒生成的进程数,平均每秒新建80多个进程,应该就是它了。
要抓出频繁建立短时进程的应用,可以采用 execsnoop ,该工具通过 ftrace 实时监控进程的 exec() 行为,并输出短时进程的基本信息, 包括进程 PID/PPID 、命令行参数。
1 2 3 4 | #下载execsnoop# cd /usr/bin wget https://raw.githubusercontent.com/brendangregg/perf‐tools/master/execsnoop chmod 755 execsnoop |
以下是输出内容,全是监控系统在执行,不停的连接 mongo 并对输出结果执行 grep 过滤,每个操作都会衍生一个新线程/进程,10s 捕获了400多条记录。
将 zabixx 进程关闭,cpu 马上恢复正常,找到了元凶。
我们其他环境也采用了 zabbix 监控,但是都没有遇到类似问题。
该节点部署了7个 mongo 实例,zabbix 默认对每个 mongo 实例都进行监控,相当于执行损耗放大了7倍,而该机器是一台只有4核CPU的虚拟机。
这些因素凑齐了就会爆发问题。这是个开发环境,暂时关闭了 zabbix 监控,后续要对监控逻辑进行优化,尽量减少连接db的次数以及 grep 调用链的长度。
3、小结
当机器 cpu 负载持续高涨却抓取不到 top 进程时,可以采用 execsnoop 抓取短时进程,类似工具还有 iosnoop、opensnoop 。