高Sys CPU的排查

问题

线上系统通过cgroup方式,将一些辅助代理进程加入到名为agent的cgroup控制组,并限定使用cpu 24。这种方式是为了避免辅助程序和应用系统争抢CPU资源。

但是,发现数十个辅助程序绑定到cpu 24之后,这个CPU出现了非常严重的sys使用率,从top来看,系统load average负载非常高,但是实际上除了少数cpu确实计算较为繁忙,大多数cpu都是空闲的。

top - 22:35:20 up 50 days,  8:33,  2 users,  load average: 40.91, 41.86, 42.51
Tasks: 7101 total,  38 running, 7058 sleeping,   0 stopped,   5 zombie
Cpu0  :  0.0%us,  0.0%sy,  0.0%ni, 88.4%id, 11.6%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu1  :  0.0%us,  3.7%sy,  0.0%ni, 95.0%id,  1.3%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu2  : 21.7%us,  6.2%sy,  0.0%ni, 69.1%id,  2.0%wa,  0.0%hi,  1.0%si,  0.0%st
Cpu3  : 27.6%us, 12.8%sy,  0.0%ni, 57.2%id,  0.0%wa,  0.0%hi,  2.3%si,  0.0%st
...
Cpu24 : 32.1%us, 67.6%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.3%si,  0.0%st
...
Mem:  263819896k total, 137107080k used, 126712816k free,  2005040k buffers
Swap:        0k total,        0k used,        0k free, 30639512k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
27980 root      20   0 1189m 1.0g 5148 S 107.1  0.4   8049:15 qemu-kvm
32303 root      20   0 1274m 1.0g 5136 S 106.5  0.4   2790:12 qemu-kvm
 3869 root      20   0 1193m 171m 5108 S 43.6  0.1   0:05.26 qemu-kvm

有关top的使用详解请参考 top命令使用tips

  • 使用 ps 命令可以获得使用CPU较高进程(这个命令非常好,能够根据cpu使用量进行降序排序):

  • 由于cpu 24上的某个程序(如果我推测没有错的话)导致CPU大量消耗sys,并且导致运行队列过长,所以临时将所有的进程都迁移到另一个控制组service中(这个service控制组分配了多个CPU资源,可以承担较大负载)

果然可以看到,sys被分担到CPU 2-5,26-29 上,此时可以看到这8个CPU上sys大量增加。不过好在有8个CPU分担,没有造成CPU完全满负荷,所以可以看到运行队列立即得到缓解,系统load average从原先40以上下降到10以下。

经过对比,发现导致load average非常高的原因是cpu 24存在阻塞:这个CPU异常高的sys完全消耗了CPU资源,导致任务在运行队列中很长。

停止部分cpu 24上的辅助程序,可以看到load average明显下降(因为减少了运行队列长度),但是sys始终保持在70%,白白浪费了CPU资源。

我的目标是找出导致如此高的sys消耗的程序,解决辅助程序堆积在运行队列中导致load average过高问题。

查找占用sys的进程

暂时还没有找到如何根据CPU来观察进程CPU占用的方法(需要同时观察ussys

  • 最初我想通过排除方法来找异常进程

上述命令将所有在cpu 24上运行的命令都找出来,然后想一一尝试从agent这个cgroup中移出,看移除掉哪个进程sys能够恢复正常比例就能够定位异常程序。

  • 创建2个控制组testjail控制组,分别绑定cpu 24cpu 25。需要测试的进程加入test控制组,测试完的所有进程都放到jail控制组,这样可以保持cpu 24只有一个进程运行和测试

  • 现在我们通过以下脚本cg_cpu.sh命令逐个将进程迁移到cpu 24上(即加入到agent控制组),看究竟是那个程序移动后出现sys的改变。测试完成后,再将进程移动到cpu 25(即加入到jail控制组),对比不同进程就可以知道哪个进程程序存在异常。

例如:

要将进程限制到cpu 24上运行(控制组agent),则执行

要将进程限制到cpu 25上运行(控制组jail),则执行

检查运行进程队列方法

可以列出所有运行队列中进程,如果有进程D住,则很容易排查。

使用stracegdb排查程序消耗sys的原因

一个应用服务器最高效的方式是尽可能使用用户层CPU时间(或者是user或者是nice),所以如果CPU时间被用于kernel(system)则表明存在一些设计上或者编码上的缺陷,或者系统此时有很严重的I/O问题。

topsar检查中非常高的%system表示程序执行在系统层(内核),这个字段表示消耗在硬件服务和软件中断上的时间。这意味着系统把相当大的时间消耗在内核代码上。

常用debug程序占用高CPU的工具有:perf, sysrq, oprofile, vmcore 等。

既然通过上述方法找出了异常的程序,我们现在来排查为何程序这样消耗sys。

  • starce统计系统调用

strace工具可以检测出如果部分调用过多的问题。这个工具特别适合debug,因为它记录了进程使用系统调用。strace的计数选项(-c)提供了一些性能上的诊断信息,这样就可以从系统调用的CPU时间来查看。

此时提示

过一会按下ctrl-c终止,输出如下

上述案例显示主要调用的系统调用是 nanosleep ,占用了进程系统调用的 78.95%;剩下的系统调用是21.05%的系统调用restart_syscall

参考NANOSLEEP(2)

nanosleep()挂起调用线程的执行直到通过*req指定的时间过去,或者发生一个信号处理器触发调用线程或终止进程。如果是信号处理器触发的中断调用,nanosleep()返回-1,设置errnoEINTR,并将剩余时间记录到rem的结构中,除非remNULL。这个*rem记录的值将在nanosleep()在此调用是使用以完成刚才的暂停。

为何程序进入睡眠会导致这么高的system占用?

  • gdb输出进程堆栈

上述命令可以输出程序堆栈,以便做分析

通过crash分析

如果系统crash并且dump出了vmcore(vmcore是通过kdump这样的工具dump出内存),可以参考以下方法来排查vmcore

分析方法参考 内核core dump分析

使用perf工具

参考

Last updated

Was this helpful?