

























最近接到一个客户反馈,说他们的机器,遇到了top命令中,hardirq的值特别高的问题。
top - 15:27:37 up 43 days, 3:42, 1 user, load average: 44.75, 53.47, 51.66
Tasks: 244 total, 1 running, 243 sleeping, 0 stopped, 0 zombie
%Cpu0 : 10.3 us, 19.8 sy, 0.0 ni, 39.7 id, 0.4 wa, 28.2 hi, 1.6 si, 0.0 st
%Cpu1 : 10.7 us, 21.3 sy, 0.0 ni, 40.7 id, 0.4 wa, 26.1 hi, 0.8 si, 0.0 st
%Cpu2 : 10.0 us, 19.1 sy, 0.0 ni, 41.4 id, 0.4 wa, 27.9 hi, 1.2 si, 0.0 st
%Cpu3 : 10.4 us, 20.7 sy, 0.0 ni, 40.2 id, 0.4 wa, 26.7 hi, 1.6 si, 0.0 st
%Cpu4 : 10.4 us, 15.5 sy, 0.0 ni, 45.4 id, 0.4 wa, 28.3 hi, 0.0 si, 0.0 st
%Cpu5 : 10.8 us, 21.9 sy, 0.0 ni, 39.4 id, 0.4 wa, 27.1 hi, 0.4 si, 0.0 st
%Cpu6 : 10.1 us, 18.6 sy, 0.0 ni, 41.7 id, 0.4 wa, 28.7 hi, 0.4 si, 0.0 st
%Cpu7 : 10.6 us, 25.2 sy, 0.0 ni, 36.6 id, 0.0 wa, 26.4 hi, 1.2 si, 0.0 st
从top命令输出可以看到,hardirq的值特别高,超过了25%。这导致了idle的下降,触发了监控的频繁报警。
而同样业务以及相似的业务量情况下,另外一台机器表现就正常许多:
top - 15:31:19 up 118 days, 20:15, 1 user, load average: 93.25, 74.45, 63.84
Tasks: 209 total, 1 running, 208 sleeping, 0 stopped, 0 zombie
%Cpu0 : 5.5 us, 18.2 sy, 0.0 ni, 76.4 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu1 : 2.8 us, 6.0 sy, 0.0 ni, 90.8 id, 0.0 wa, 0.0 hi, 0.4 si, 0.0 st
%Cpu2 : 6.6 us, 19.8 sy, 0.0 ni, 72.7 id, 0.4 wa, 0.0 hi, 0.4 si, 0.0 st
%Cpu3 : 2.4 us, 6.3 sy, 0.0 ni, 91.4 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu4 : 5.9 us, 17.4 sy, 0.0 ni, 76.7 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu5 : 2.4 us, 7.1 sy, 0.0 ni, 90.6 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu6 : 5.0 us, 18.7 sy, 0.0 ni, 76.3 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu7 : 2.4 us, 6.7 sy, 0.0 ni, 90.6 id, 0.4 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu8 : 5.1 us, 16.8 sy, 0.0 ni, 77.6 id, 0.0 wa, 0.0 hi, 0.5 si, 0.0 st
这俩机器在业务性能表现上是类似的,最大的区别就是hardirq高的机器使用了更新的RockyLinux 9操作系统,内核版本会新一点。而另一台机器还在使用老的CentOS 7操作系统,内核版本会老一点。
除了Rocky 9机器hardirq高之外,两台机器的其他各方面指标都非常的相似,比较明显的,两台机器的中断数量以及context switch数量都比较高:
~]$ dstat -y
---system--
int csw
364k 1247k
358k 1242k
384k 1271k
547k 1480k
562k 1505k
上下文切换超过了100万次/s。两者的火焰图也十分相似,不过从火焰图上观察,进程会大量调用nanosleep这个系统调用,调用比例和hardirq的比例是类似的:

如果是大量nanosleep调用的话,那应该很容易用stress-ng工具复现了。事实证明,使用stress-ng工具可以获得和生产环境非常相似的现象,尝试了Rocky 9.5、CentOS 7.9,物理机、虚拟机的各种组合,结果发现确实和操作系统的内核版本关系很大。
在后续分析中,找到了这样一篇资料Is Your Linux Version Hiding Interrupt CPU Usage From You?。
在这篇文章中,作者发现Ubuntu 20.10及其默认Linux内核5.8.0版本的系统中,即使使用fio压测实现了11M IOPS的性能时,dstat和其他监控工具报告的hardirq时间依然为零,而在相同的机器上启动了使用Oracle Enterprise Linux 8.3及5.4.17版本内核时,发现hardirq时间会占用差不多27%的CPU。
这和我们遇到的问题非常相似,他给出了一个关键性的内核配置项CONFIG_IRQ_TIME_ACCOUNTING。
在作者的Ubuntu系统中,CONFIG_IRQ_TIME_ACCOUNTING配置没有被启用,同样的,这个配置在我们的CentOS 7环境里也没有启用(甚至并没有这个配置项):
$ uname -r
3.10.0-1160.el7.x86_64
$ grep CONFIG_IRQ_TIME_ACCOUNTING /boot/config-`uname -r`
$ awk '/^cpu /{ print "HW interrupt svc time " $7 * 10 " ms" }' /proc/stat
HW interrupt svc time 0 ms
而在更新的Rocky 9中,该配置被启用了:
$ uname -r
5.14.0-503.23.1.el9_5.x86_64
$ grep CONFIG_IRQ_TIME_ACCOUNTING /boot/config-`uname -r`
CONFIG_IRQ_TIME_ACCOUNTING=y
$ awk '/^cpu /{ print "HW interrupt svc time " $7 * 10 " ms" }' /proc/stat
HW interrupt svc time 432097660 ms
可以看到,启用了这个配置后,硬件中断处理程序中花费的时间才会被统计,这也是为什么线上用户会报告硬件中断处理程序中花费的时间不匹配的原因。
关于中断时间的统计,文章作者也给了一些解释,这里也翻译一下,供大家参考。
中断处理会影响任何线程的CPU时间,因为中断不关心CPU上正在运行的是什么,它们只是突然接管。这正是它们被称为中断的原因! 更长的解释如下:
首先假设 IRQ 时间统计被禁用:
现在,启用 IRQ 时间统计后:
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。