当前位置: 首页 > 科技观察

腾讯开发工程师:Linux机器CPU故障排查

时间:2023-03-18 23:32:09 科技观察

本文排查一个Linux机器CPU故障问题,故障排除过程中不改变进程状态,不影响在线服务,最后分析CPU故障带来的风险和确认。本文提到的CPU统计信息和生成核心文件的工具在simple-perf-tools仓库中有详细介绍。问题描述服务所在机器的统计信息显示其CPU使用率在高峰时段出现毛刺。暂时没有收到来自服务调用者的不良反馈。初步排查CPU的1分钟平均负载,发现1分钟平均负载由高变低,波动明显。就是说机器上有一些进程使用CPU波动很大。登录机器查看进程,使用top命令。因为CPU会显着增加,所以怀疑使用高总CPU时间的进程很重要。打开top后,使用shift+t按CPUTIME排序。直观上,几个spp_worker相关的进程使用了??比较高的CPUTIME。因为第一个进程启动时间比较长,CPUTIME也比较大。可以使用如下脚本计算每个进程拉起后的CPU使用率:uptime=`awk'{print$1}'/proc/uptime`#whyisittooslowwindocker?hertz=`zcat/proc/config.gz|grepCONFIG_HZ=|awk-F"="'{print$2}'`awk-vuptime=$uptime-vhertz=$hertz--'{printf("%d\t%s\t%11.3f\n",$1,$2,(100*($14+$15)/(hertz*uptime-$22)));}'/proc/*/stat2>/dev/null|sort-gr-k+3|head-n20也看到了这些spp_workers的使用CPU占用率相对较高:选择其中一个PID为45558的Worker进程监控CPU占用率:可以发现大部分CPU占用率较低,但会在某个时间点上升,持续1秒左右。而且大部分时间都花在了用户态,而不是系统调用。《Linux Agent 采集项说明 - CPU 使用率》中描述的CPU使用率采样策略是:LinuxAgent每分钟收集4次15秒内的平均CPU使用率。为了避免漏掉CPU峰值采集,网管代理在一分钟内取四次采集的最大值上报。因为采样有高有低,当1分钟内有CPU飙升时,会出现一个峰值;如果没有四次激增,它就会出现一个低谷。至此,已经确认是这批Worker进程导致了故障,具体是哪部分代码有问题,还需要进一步排查。进一步调查确认没有太多的系统调用,所以没有必要使用strace工具。使用perf工具使用perf工具查看。具体命令是perftop-p45558,CPU使用率低的时候:但是当CPU上升的时候,perf采样的位置就变成了这样:看红框的位置,可以发现可能有configurationupdate部分的一些错误问题是因为:这个地方有很多Protobuf,并且在做update操作(有MergeFrom,有Delete)。通过观察perf结果,有很多std::maps(有std::_Rb_tree,有字符串比较)。该方法虽然可以猜出计算量大的位置,但有两个不便之处:如果高CPU的概率很低,人工观察很费时间,无法清楚地知道哪个文件中的哪个函数使用了gcore初始统计当发现CPU高时,需要1秒以上。如果发现CPU负载过重,可以直接调用gcore{pid}命令保存堆栈信息,明确负载过高的具体位置。在统计工具中加入使用gcore的命令,设置CPU优先触发。通过gdb查看了几个coredump文件,发现栈和函数调用基本一致。可以清楚的看到AddActInfoV3函数中出现了大量的耗时:至此,我们已经明确了计算量大的具体位置。风险点是否存在CPU突然飙升的风险?计算资源充足就没有问题吗?本例使用SPP微线程功能,每个Worker进程只启用一个线程。如果CPU只是因为计算量大而卡住,正常处理请求的逻辑就很难调度。这将不可避免地增加处理请求的延迟,甚至有超时返回的风险。使用spp的cost_stat_tool工具,用spp自带的统计工具确认这个风险点,查看worker处理前端请求延时统计,执行命令./cost_stat_tool-r1:在上面的例子中,统计的是配置更新前后5秒2分钟内,worker处理的231个请求中,有3个请求处理时间超过500ms,远高于普通请求。使用tcpdump抓包确认服务没有开启详细日志。如果想进一步验证这些超过500ms的请求是正常处理请求,而不是异常请求,可以通过抓包分析。tcpdump-ianytcpport20391-Xs0-c5000-wservice_spp.pcap是通过wireshark打开的,需要过滤掉返回时间-请求时间>500ms的相关请求。翻译成wireshark过滤器的表达式是:tcp.time_delta>0.5&&tcp.dstport!=20391过滤出一条符合条件的请求:右键记录->关注->TCPStream,可以查看前后请求IP包:上面四个包分别是:+0msclient向server发送请求+38msserver回复ACK,无数据+661msserver返回给client+662msclient回复ACK详细阅读包内容是一个普通请求逻辑简单,应在20毫秒内返回。此时进程使用的CPU确实处于高负载:以上统计相互印证:CPU高时,正常的网络请求也会被阻塞(回复ACK需要38ms,不到40ms,并且与TCP延迟确认无关)通常只需要20ms就可以返回一个请求,但是需要660ms,CPU突然飙升,有风险,需要认真对待。