CPU负载异常的初步诊断流程
Linux服务器CPU负载过高是运维中最高频的故障类型之一。标准排查流程从top命令开始,逐层深入到进程级、线程级和函数级分析。服务器故障排查的核心原则是分层定位——先判断是系统级负载还是单进程占用,再缩小到具体线程和函数调用。
首先通过uptime确认负载趋势:
# 查看系统负载(1分钟/5分钟/15分钟)
uptime
# 输出示例:load average: 32.15, 28.40, 12.05
# 1分钟负载远高于15分钟,说明负载在近期急剧上升
负载值本身不能直接判断是否异常,需要结合CPU核心数。一台32核服务器,load average为32属于满载但不一定异常;同样的负载在4核服务器上则是严重过载。快速获取核心数和当前负载的比值:
# 获取CPU核心数
nproc
# 计算负载比
echo "$(cat /proc/loadavg | awk '{print $1}') / $(nproc)" | bc -l
负载比超过1.0时需要关注,超过2.0时需要立即排查。但load average包含等待I/O的进程(D状态),高负载不一定等于CPU计算密集,需要进一步区分。
top命令定位高CPU进程
top是最常用的实时监控工具,但多数人只用基础功能。高CPU排查时,需要调整top的显示参数以获取更多信息。
# 启动top,按以下顺序操作
top
# 1. 按 P 键:按CPU使用率排序
# 2. 按 H 键:显示线程级信息
# 3. 按 1 键:展开显示每个CPU核心的使用率
# 4. 按 f 键:添加显示字段(如 nTGID, CGNAME)
展开CPU核心视图后,关注两个指标:us(用户态CPU)和sy(内核态CPU)。us高说明应用程序计算密集,sy高说明系统调用频繁或存在内核锁竞争。如果si(软中断)高,通常是网络收发包压力导致。
定位到高CPU进程后,记录PID。使用以下命令查看进程的线程级CPU分布:
# 方法1:top -H 查看指定进程的线程
top -H -p <PID>
# 方法2:ps查看线程CPU使用率
ps -L -p <PID> -o tid,%cpu,comm --sort=-%cpu | head -20
# 方法3:查看进程的线程调用栈
cat /proc/<PID>/status | grep Threads
# 确认线程数量是否符合预期
perf工具采集性能热点
top只能定位到进程和线程级别,要分析到函数级热点需要使用perf。perf是Linux内核内置的性能分析工具,能够采集CPU性能计数器和调用栈信息。
采集CPU热点数据:
# 安装perf(不同发行版包名不同)
# CentOS/RHEL: yum install perf
# Ubuntu/Debian: apt install linux-tools-common linux-tools-$(uname -r)
# 采集全系统CPU热点,持续30秒
perf record -F 99 -ag -- sleep 30
# 采集指定进程的CPU热点
perf record -F 99 -p <PID> -- sleep 30
# 查看热点报告
perf report --stdio
perf report输出中关注Overhead列,表示该函数占总CPU时间的百分比。排序后前几个函数就是性能热点。常见的高频热点函数:
- memset/memcpy:内存操作频繁,可能是数据结构设计不当
- mutex_spin_on_owner:锁竞争严重,多线程争抢同一把锁
- __do_softirq:软中断处理频繁,通常是网络中断负载
- system_call_fastpath:系统调用过多,可能是频繁的I/O操作
火焰图可视化分析性能瓶颈
perf report的文本输出不够直观,火焰图(Flame Graph)能将调用栈可视化为层次结构图,快速定位热点函数所在调用链。
# 1. 安装火焰图工具
git clone https://github.com/brendangregg/FlameGraph.git
cd FlameGraph
# 2. 采集perf数据(需要调用栈)
perf record -F 99 -ag --call-graph dwarf -- sleep 30
# 3. 生成折叠格式的调用栈数据
perf script | ./stackcollapse-perf.pl > out.perf-folded
# 4. 生成火焰图SVG
./flamegraph.pl out.perf-folded > cpu_flamegraph.svg
火焰图的阅读方法:横轴表示函数调用的CPU时间占比,纵轴表示调用栈深度(底部是调用方,顶部是被调用方)。重点关注横向最宽的”平台”,这些是消耗CPU时间最多的函数。如果顶部是一根很窄的”尖刺”,说明调用层次深但单次执行时间短,优化价值和优先级较低。
DWARF模式采集调用栈会比fp模式更准确,但性能开销更大(约5-10%的CPU开销)。生产环境采集时建议在低峰期执行,或缩短采集时间到10秒以内。
iowait与CPU负载的区分排查
服务器故障排查中,高负载不等于高CPU计算。当top显示高load average但us不高,wa(iowait)偏高时,瓶颈在磁盘I/O而非CPU。这种情况下perf采集CPU热点意义不大,需要转向I/O分析。
# 查看各CPU状态分布
mpstat -P ALL 1 5
# 关注%iowait列,如果持续超过20%,说明I/O是瓶颈
# 查看磁盘I/O情况
iostat -xz 1
# 关注%util和await列
# %util接近100%且await高,说明磁盘过载
# 查找正在等待I/O的进程
ps -eo state,pid,cmd | grep "^D"
# D状态(不可中断睡眠)的进程正在等待I/O
确认I/O瓶颈后,排查方向转向磁盘性能和应用程序的I/O模式。常见原因包括:日志写入未做异步缓冲、数据库全表扫描导致大量磁盘读取、swap未关闭导致频繁换页。硬件性能测评时,SSD随机读写IOPS不足也会表现为此类问题。
对于swap导致的伪CPU负载,检查并临时关闭:
# 查看swap使用情况
free -h
swapon --show
# 如果swap被大量使用,查看使用swap的进程
for file in /proc/*/status; do
awk '/VmSwap|^Name/{printf $2 " " $3}END{ print ""}' $file
done | sort -k2 -n -r | head -10
# 临时降低swap倾向(0=最不倾向使用swap)
sysctl vm.swappiness=10
常态化监控与告警配置
单次排查解决的是已发生的故障,常态化监控才能在故障发生前预警。Linux系统管理中,推荐搭建Prometheus + node_exporter监控体系,配置CPU相关的告警规则。
# Prometheus告警规则示例:CPU负载告警
groups:
- name: cpu_alerts
rules:
- alert: HighCpuLoad
expr: node_load1 / count without(cpu, mode) (node_cpu_seconds_total{mode="idle"}) > 1.5
for: 5m
labels:
severity: warning
annotations:
summary: "CPU负载过高 {{ $labels.instance }}"
description: "1分钟负载/核心数比值为 {{ $value }},超过1.5"
- alert: HighCpuUsage
expr: 100 - (avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
for: 10m
labels:
severity: critical
annotations:
summary: "CPU使用率超过80%持续10分钟"
告警阈值设定需要基于历史数据。先采集两周的正常运行数据,统计P95和P99值,在此基础上设置告警阈值。过低的阈值会导致大量误报,运维人员产生告警疲劳;过高的阈值会导致漏报,错过早期干预窗口。服务器安全加固中,还需监控异常进程的CPU占用,防止挖矿木马等恶意程序潜伏。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/linux-fu-wu-qi-cpu-fu-zai-guo-gao-pai-cha-quan-liu-cheng/