​Linux CPU性能优化:常见CPU性能问题及解决方案

嘿,让我告诉你一件事。
当我处理Linux服务器时,CPU问题确实是一个令人头疼的问题。
但经过十年的努力,我终于发现了其中的缺陷。
我们不要解决问题。
我们来谈谈真实的事情。

例如,我在上海工作了一年,帮助客户为电子商务业务配置服务器。
这家伙的CPU像火箭一样增加,但是系统负载(正常运行时间数字)实际上并不高。
当时我就很困惑,以为出了什么问题。
既然 CPU 已经在这样做了,为什么不能继续加载呢?后来我盯着看,发现大部分进程都挂了。
条件为D,发现不能被打扰。
经过检查,发现数据库查询速度慢,硬盘读取数据困难。
硬盘IO跟不上,担心CPU也没用。
系统负载自然不会体现出来。
CPU 使用率应该与系统负载和 IO 条件一起考虑,这是有道理的。

再举个例子,去年我在北京为一个进行人工智能培训的团队做服务器工作。
我们使用压力测试CPU,结果CPU使用率1 00%,系统负载暴涨。
只需使用 mpstat 查看即可发现,对于大多数用户模式任务而言,一个核心已满成立。
这个时候,你就得用pidstat来一一查看进程了。
事实证明,某些模型的推理代码会导致无限循环。
改了之后就没事了。
这让我意识到压力是一个很好的工具,可以帮助你快速找到问题。

还有一次,我帮杭州的客户架设了虚拟机。
我刚刚安装了虚拟机,用压力来模拟IO压力。
因此,CPU 使用率并不明显。
无法增加系统负载。
我想到了这一点。
这个虚拟机磁盘快了,内存还在磁盘闪动操作(同步)根本无法被抑制。
后来改用stress-ng,指定使用机械硬盘模拟。
现在好了 CPU 起来了,系统负载也增加了。
这表明选择正确的工具和参数的重要性。

话虽如此,让我们总结一些要点:
1 不要单独看系统负载和CPU使用率。
上海的服务器就是一个例子。
虽然CPU很忙。
低负载是因为没有生成足够的“可执行进程”。
2 .压力是一件好事。
它是CPU,它可以强调IO和进程数。
当时我用stress-c1 模拟了北京的CPU压力和uptime来发现问题。
mpstat 和 pidstat使用了顶部。
3 . 针对 IO 问题选择正确的工具。
当时杭州的虚拟机同步失败,所以换成了stress-ng。
4 .内容切换很重要。
我在深圳住过一年,服务器的CPU负载不高,但是转cs的上下文很高。
后来发现有些服务频繁等待I/O,导致大量非自愿切换。
我使用 vmstat 和 pidstat 来检查该服务的问题。
我调整了I/O缓冲策略,转换次数立即下降。
5 、缓存命中率还取决于缓存命中率。
它并不常用,但如果 CPU 缓存未满,它可以对性能产生很大的影响。
我在成都的时候,帮一个做数据分析的客户调代码,发现他们的代码访问大对象频繁,一级缓存命中率低。
我们要求他们调整数据结构并整合经常访问的数据。
提高缓存命中率后; CPU性能直接提升。

简而言之,在排除 CPU 问题时;不要只关注一项指标。
系统负载CPU使用率;改变内容; IO消耗;有时整合缓存命中率可以帮助您找到问题的根源。
如果你是顶级的, mpstat pidstat 使用正确的工具,如 vmstat 和 uptime、stress, 结合压力测试工具,如stress-ng 和 sysbench。
你可以追根溯源。

Softlockup和Hardlockup介绍和定位思路总结

坦率地说,要理解Linux内核中的锁定问题,必须分开考虑软锁定和硬锁定。
以前我的服务器出了问题,差点因为硬锁而整台电脑坏掉,所以我需要详细讨论这个问题。

我们先来谈谈软键。
这很常见。
上次我测试新的驱动系统时,遇到了软锁。
CPU被某个内核线程卡住但中断仍能正常响应。
如何检测原子核?它为每个CPU运行一个实时线程(watchdog/x),并且该线程具有非常高的优先级(9 9 级)。
如果在设定的时间内没有开始运行,则判定为软锁定。
默认超时阈值是双 watchdog_thresh,例如默认为 1 0 秒,软锁为 2 0 秒。
我查看了日志,发现某些USB驱动程序的扫描功能卡在那里,因为设备从未响应,导致扫描无休止地重复。

封锁更加严重。
我参与了内核崩溃分析,机器在硬锁后甚至没有响应 NMI。
锁定检测原理比较复杂,依赖于PMU的NMI事件。
内核会检查hrtimer_interrupts时钟中断计数器,如果计数器停止工作,就会触发锁定警告。
记得有一次分析一个存储阵列的错误,发现某个FAD控制器的驱动程序在处理SCSI命令时被锁定,因为它在持有某个keylock的同时禁用了中断,导致CPU完全挂起。

我对配置印象非常深刻。
nmi_watchdog是硬锁检测开关和软锁监测管。
我曾经在调整生产系统时注意到频繁的软件死机,因此我将soft_watchdog设置为1 并打开nmi_watchdog。
但有一个陷阱。
必须先在主交换机看门狗中配置 watchdog_cpumask,然后才能指定要监视的 CPU。
我有一个使用4 核CPU的项目。
起初,我只启用了对核心 0-1 的监控。
然而2 -3 核的问题却没有被发现,差点酿成大错。

定位思路也很实用。
对于软键,我建议直接查看 dmesg 输出。
上次我查看网卡驱动程序中的无限循环时,内核打印的调用堆栈直接指向轮询某些错误的函数。
有时完美会有所帮助。
例如,当我分析网络协议栈崩溃时,perf 记录了 CPU 时间,并发现某个 IP 层功能在处理特定数据包时陷入困境。

硬锁就麻烦多了。
我分析了一个内核线程死锁导致的硬锁,直接看到调用栈中local_irq_disable没有解锁代码。
我正在处理的一个更复杂的情况是由竞争性多任务引起的问题。
任务A关闭中断然后退出。
任务 B 突然需要处理中断。
结果,中断系统变得混乱并锁定。
在这种情况下,您必须使用 Ftrace。
那次我使用 irqsoff 监视器,注意到一些锁竞争导致关闭中断时间过长。
最后我在驱动中添加了锁优化来解决问题。

我想提出两个优化建议。
首先,不要在内核代码中编写无限循环。
我见过一些项目因为误判某个条件而导致软锁。
其次,调整 watchdog_thresh 很重要。
我已经调整了过载的云服务器。
默认 2 0 秒太短。
改为3 0秒后,软锁时间明显减少。
但请注意,将阈值设置得太高可能会隐藏问题,必须根据实际负载进行调整。

总的来说,虽然软锁和硬锁都是CPU的问题,但是解决方案却完全不同。
要软锁,只需查看调用堆栈即可。
要进行硬锁定,您需要测试中断行为。
我建议系统管理员使用看门狗来执行定期自检,尤其是在内核升级之后。
我之前带领团队建立了每月运行一次软锁检测的流程,提前发现了很多潜在的问题。