CPU高负载场景调优实战
一、 CPU软中断(softirq)过高
问题现象:
top
或pidstat
显示%system
系统态CPU使用率很高。top
下看到ksoftirqd/0
,ksoftirqd/1
等进程占用大量CPU。网络吞吐量下降,应用延迟增加。
排查工具与方法:
查看软中断分布:
watch -d 'cat /proc/softirqs'
观察点: 关注
NET_RX
(网络接收)和NET_TX
(网络发送)的变化率。如果某一项在飞速增长,说明网络包处理是瓶颈。其他项:
TIMER
(定时器),BLOCK
(块设备)等。
使用
mpstat
查看各核心中断分布:mpstat -P ALL 1
观察点: 看是否所有核心的
%soft
都高,还是集中在某一个核心上。如果集中在一个核心上,就是软中断不均衡问题。
深入分析:
原因: 通常是高网络流量导致单个CPU核心处理不过来的网络软中断。
解决方案:
开启RPS/RFS: 在软件层面将网络中断负载均衡到多个CPU核心。
使用更先进的中断模式: 如
irqbalance
服务,或者使用ethtool
调整网卡的多队列配置。
二、 不可中断睡眠(D状态)进程
问题现象:
top
或ps
看到进程状态为D
。这种状态的进程无法被杀死。系统负载可能很高,但CPU使用率不一定高。
执行
ls /proc/*/wchan
可以看到很多进程卡在io_schedule
之类的内核函数上。
排查工具与方法:
定位D状态进程:
ps -eo pid,ppid,state,comm | grep '^.* D'
分析IO等待:
iostat -x 1
观察点: 查看
%util
和await
。如果%util
持续100%,且await
非常高,说明存储设备已经完全饱和,IO请求堆积。
使用
strace
尝试跟踪:strace -p <D_state_pid>
注意: 对于D状态进程,
strace
很可能也卡住,但这本身也印证了进程正在等待一个无法返回的IO调用(例如有故障的NFS服务器或硬盘)。
使用
perf
查看内核调用栈:sudo perf record -g -p <pid> sudo perf report
查看进程卡在哪个内核函数上,通常是
__x64_sys_read
、blkdev_direct_IO
等。
解决方案:
通常是底层存储问题。需要重启服务器或修复存储链路。
如果是NFS挂载点问题,可以尝试
umount -f
强制卸载。
三、 进程优先级(Nice值)和实时优先级(RT Priority)不当
问题现象:
某个低优先级的后台任务(如备份、编译)占满CPU,导致前台交互式应用卡顿。
排查工具与方法:
查看进程的Nice值和实时优先级:
ps -eo pid,ni,rtprio,comm
NI
列: Nice值,范围 -20(最高优先级)到 19(最低优先级)。普通用户只能调低优先级(增加Nice值)。RTPRIO
列: 实时优先级,范围 1(最低)到 99(最高)。如果显示-
,表示是普通调度策略。
使用
top
查看:在
top
中,按r
可以动态调整一个进程的Nice值。按
f
,然后按G
(P = PGRP) 或H
(I = ITH),可以显示进程所在的调度策略。
修改进程优先级:
调整Nice值:
# 启动时设置 nice -n 10 /path/to/backup_script.sh # 运行时调整 renice -n 10 -p 1234
设置实时优先级(需要root):
chrt -f -p 90 1234 # 将PID 1234设置为SCHED_FIFO策略,优先级90
警告: 错误地使用实时优先级可能导致系统锁死,因为它会抢占所有普通进程和内核线程。
四、 内存不足引发的调度问题(OOM Killer相关)
问题现象:
系统负载极高,
vmstat
中si
/so
(swap in/out)很高。应用性能急剧下降。
进程突然消失,系统日志
/var/log/messages
或dmesg
中看到Out of memory: Kill process ...
的信息。
排查工具与方法:
检查内存和Swap使用:
free -h cat /proc/meminfo | grep -iE "(MemFree|SwapCached)"
查看OOM Killer日志:
dmesg -T | grep -i "killed process"
分析每个进程的内存开销:
# 按内存使用排序 ps -eo pid,ppid,%mem,rss,comm --sort=-%mem | head
理解OOM Killer评分:
内核会根据
oom_score
来决定杀死哪个进程。你可以查看这个分数:
cat /proc/<pid>/oom_score
通常,内存占用多、且不太重要的进程得分会更高。
解决方案:
增加物理内存或优化应用内存使用。
通过
/proc/<pid>/oom_adj
或/proc/<pid>/oom_score_adj
来调整特定进程的OOM权重,保护关键进程。
五、 CGroup 引起的CPU限制
问题现象:
容器的性能达不到预期,即使宿主机CPU很空闲。
在容器内跑
top
发现CPU使用率不高,但应用就是慢。
排查工具与方法:
在宿主机上查看容器的CGroup CPU配置:
# 找到容器的CGroup路径 docker inspect <container_id> | grep -i cgroup # 查看CPU配额 cat /sys/fs/cgroup/cpu/<cgroup_path>/cpu.cfs_quota_us cat /sys/fs/cgroup/cpu/<cgroup_path>/cpu.cfs_period_us
cpu.cfs_quota_us / cpu.cfs_period_us
就是该容器能使用的CPU核心数上限。例如100000 / 100000 = 1
,表示限制为1个核心。
查看CPU统计信息:
cat /sys/fs/cgroup/cpu/<cgroup_path>/cpu.stat
关注
nr_throttled
(被限制的次数)和throttled_time
(被限制的总时间)。如果这两个值很高,说明容器频繁触发了CPU上限。
解决方案:
在启动容器时调整
--cpus
参数,增加CPU配额。
总结
这些高级的CPU和调度问题,要求运维工程师不仅会看 top
,还要理解:
内核子系统如何交互: 比如IO如何通过中断、软中断影响CPU;内存不足如何触发OOM Killer。
资源隔离机制: 如CGroup如何限制容器资源。
更底层的观测工具: 如
mpstat
,/proc/softirqs
, CGroup文件系统等。