6个Linux CPU调优实战技巧,第三个帮你解决CPU飙升
一、什么时候需要CPU调优?
- 服务响应变慢,
top看到CPU us或sy持续超过70% - 机器load average高于CPU核心数*2
- 你怀疑某个进程占用了太多CPU,想限制它或给它提权
- 虚拟化环境里
%steal高,说明宿主机超售严重
读完这篇你会:能判断CPU瓶颈的类型,会用工具定位热点,敢动手改内核参数。
前置条件:能登录Linux服务器,有root权限。我用Ubuntu 22.04(内核5.15)和CentOS 7(内核3.10)都测过。
二、先把指标看懂,别瞎调
2.1top的第一行 load average
load average: 2.50, 3.10, 4.20这三个数分别是1分钟、5分钟、15分钟的平均活跃进程数(正在运行+等待运行的进程)。注意:它不是CPU使用率。
怎么判断load高不高?拿CPU核心数比较。比如4核机器,load < 4 算正常;超过8说明有大量进程在排队。
坑:load高但CPU idle也高,说明进程卡在I/O或锁上(比如磁盘慢、网络等待)。这时候调CPU没用。
2.2top的CPU状态行
%Cpu(s): 12.5 us, 3.2 sy, 0.0 ni, 84.0 id, 0.2 wa, 0.0 hi, 0.1 si, 0.0 st字段 | 含义 | 正常范围 |
us | 用户态(应用代码) | 视业务,长期>80%考虑优化代码 |
sy | 内核态(系统调用、驱动) | 通常<10%,过高可能锁竞争或驱动问题 |
ni | nice值调整过的进程用户态 | 一般很小 |
id | 空闲 | 越高越好 |
wa | 等待I/O | 超过5%说明磁盘是瓶颈,别调CPU |
hi | 硬件中断 | 通常<1%,过高可能网卡中断风暴 |
si | 软件中断 | 通常<3%,过高可能网络流量大或驱动问题 |
st | 虚拟机偷走的时间 | 云上常见,>5%说明宿主机超售严重 |
2.3 我推荐的一键看全局命令
# 每秒刷新,显示CPU、内存、磁盘、网络 vmstat 1 5 # 重点看:r(运行队列),b(阻塞进程),cs(上下文切换),in(中断),us,sy,id,wa预期输出(示例):
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 2 0 0 204800 10240 512000 0 0 10 20 500 8000 15 3 82 0 0cs(上下文切换)如果超过几万,说明线程频繁切换,考虑减少线程数或绑核。
三、定位CPU热点:谁在吃CPU?
3.1 用top找到最猛的进程
top -o %CPU # 按CPU排序记下PID,然后看它的线程:
top -H -p PID3.2 用pidstat看每个线程的CPU占用
pidstat -t -p PID 1 # 每秒输出,-t显示线程如果某个线程一直很高,记下TID(线程ID)。
3.3 用perf看热点函数(终极武器)
# 采样30秒,看CPU在哪里花时间 perf top -p PID # 或者记录后分析 perf record -p PID -g -- sleep 30 perf report你会看到一个火焰图式的调用栈。我当初用这个发现程序在疯狂调用strlen(),原来是日志打印太频繁。
彩蛋:如果没装perf,试试strace -c -p PID,看系统调用耗时。不过strace开销大,生产慎用。
四、调优手段:从软到硬
4.1 调整进程优先级(nice)
nice值范围-20到19,越低优先级越高。普通用户只能调高(降优先级),root能调低(提权)。
# 启动时指定nice nice -n -10 ./my_app # 调整已运行的进程 renice -n -5 -p 1234我推荐:I/O密集型的数据库进程可以给高优先级(比如-10),而备份脚本给低优先级(19)。
4.2 绑核(CPU亲和性)
避免进程在核心间频繁迁移,提高缓存命中率。
# 查看进程当前绑定情况 taskset -p PID # 绑定到CPU 0,2(掩码0b0101=5) taskset -p 5 PID # 启动时绑定 taskset -c 0,2 ./my_app注意:别把关键进程和网络中断绑在同一个核。我一般把网卡中断绑到最后一个核,应用绑到前几个。
4.3 调整内核调度参数(高手向)
这些参数在/proc/sys/kernel/下,临时修改用sysctl -w,永久写/etc/sysctl.conf。
# 查看CFS调度器的唤醒抢占粒度(默认4ms) cat /proc/sys/kernel/sched_wakeup_granularity_ns # 减少抢占粒度,提高交互性(但吞吐会降) sysctl -w kernel.sched_wakeup_granularity_ns=2000000我一般不碰这些,除非你有非常明确的场景(比如实时音视频)。乱调可能让系统行为变得诡异。
4.4 限制进程CPU使用(cgroup)
用systemd或cgroup v2限制某个服务占用不超过2个核。
# 创建一个cgroup(cgroup v1) cgcreate -g cpu:/limited cgset -r cpu.cfs_quota_us=200000 limited # 2核(200ms内给200ms) cgset -r cpu.cfs_period_us=100000 limited # 把进程放进去 cgclassify -g cpu:/limited PID用systemd更简单:编辑service文件,加CPUQuota=200%。
五、实战案例:Nginx CPU飙升到100%
场景还原
某天top看到nginx的CPU使用率100% us,但流量没涨。重启后一会儿又上去。
排查过程
pidstat -t -p $(pidof nginx) 1看到worker线程CPU高。perf top -p 那个线程PID,发现热点在ngx_http_log_handler。- 检查nginx配置,发现access_log里用了
$request_time,而且日志级别开了debug。 - 注释掉debug,把日志格式简化,CPU降到5%。
教训:日志格式里计算变量(比如$request_time)会消耗CPU。生产环境别开debug。
六、彩蛋:几个你可能不知道的CPU调优命令
lscpu看CPU型号、核心数、NUMA拓扑。numactl --hardware看NUMA节点内存分布。跨节点访问内存慢,绑核时尽量用同节点的内存。irqbalance服务自动分配中断到不同CPU,但有时手动绑定效果更好。cpupower frequency-set -g performance把CPU频率策略设为性能模式(笔记本默认是powersave)。
我踩过的坑:在虚拟化环境(KVM)里,宿主机超售太多,你调guest没卵用。找云服务商换独享型实例。
七、验证调优效果
调完别重启就走。用压测工具跑一下:
# 安装stress sudo apt install stress # 制造4个CPU满负荷 stress --cpu 4 --timeout 60 # 同时用mpstat观察 mpstat -P ALL 1如果负载能压满且%sys不异常,就算及格。
生产验证:灰度切流量,观察半小时,对比调优前后的平均响应时间和CPU使用率。
八、常见问题(真有人问过我)
Q:load average很高,但top里CPU idle也高,为什么?
A:进程在等I/O(磁盘、网络),或者被锁阻塞。用iostat -x 1看%util,或者pidstat -d看进程读写。
Q:改nice值会影响其他进程吗?
A:会。你给A提权,B就相对被降权。别在生产环境随便renice -20,除非你确定A非常重要。
Q:perf报No permission?
A:内核参数kernel.perf_event_paranoid默认2,普通用户不能用。临时调成1:sysctl -w kernel.perf_event_paranoid=1。或者用sudo perf。
Q:我的CPU支持超线程,应该把两个逻辑核当同一个物理核看待吗?
A:对于计算密集型任务,建议两个逻辑核不要同时满负荷,否则会争抢执行单元。绑核时,先查物理核ID:cat /sys/devices/system/cpu/cpu*/topology/thread_siblings_list。
九、总结一下
- 先定位,后调优:用
top、mpstat、vmstat看清瓶颈是us、sy还是wa。 - 用户态高:优化代码(减少循环、缓存结果)或调nice。
- 内核态高:看系统调用(
strace)、锁竞争(perf lock)、中断(/proc/interrupts)。 - 最后手段:加CPU、换云主机规格。
CPU调优是个细活,不要为了调优而调优。如果系统响应已经满足SLA,就别动了。
你有没有遇到过CPU调优翻车的经历?来评论区聊聊,我帮你分析。
