linux服务器排查进程CPU使用率高的思路
背景
公司的kubernetes集群服务器经常出现CPU持续升高的问题,以下是针对Linux服务器排查进程CPU使用率高的问题,进一步定位是哪个容器的CPU占用比较高
一.CPU使用率的构成
Linux系统的CPU使用率包含多个维度。
# 使用top命令查看CPU详细信息
%Cpu(s): 1.2 us, 1.5 sy, 0.0 ni, 95.5 id, 0.0 wa, 0.4 hi, 1.4 si, 0.0 st
各字段含义:
-
us (user): 用户空间进程消耗的CPU时间
-
sy (system): 内核空间消耗的CPU时间
-
ni (nice): 改变过优先级的进程消耗的CPU时间
-
id (idle): 空闲CPU时间
-
wa (iowait): 等待I/O完成的CPU时间
-
hi (hardware interrupt): 硬件中断消耗的CPU时间
-
si (software interrupt): 软件中断消耗的CPU时间
-
st (steal): 虚拟机被hypervisor偷走的CPU时间
其中需要重点关注的CPU使用率的值
-
用户态CPU高(us高):通常是应用程序代码执行导致,如死循环、复杂计算、正则匹配等
-
内核态CPU高(sy高):可能是系统调用过多、网络包处理、进程创建销毁频繁等
-
I/O等待高(wa高):磁盘I/O性能瓶颈,CPU在等待磁盘响应
-
软中断高(si高):通常与网络流量大有关,如DDoS攻击、数据传输密集等
CPU使用率100%并不代表CPU真正在"工作",wa高的情况下CPU实际是在等待,优化方向完全不同。
二.定位CPU使用率高的思路
1.定位进程
使用top命令快速定位
# 启动top并按CPU使用率排序
top -c
# 关键快捷键:
# P: 按CPU使用率排序
# M: 按内存使用率排序
# c: 显示完整命令行
# 1: 显示每个CPU核心的使用情况
截图如下

重点关注的信息:
进程PID和命令:记录占用CPU最高的进程ID和完整命令
CPU%:单个进程占用的CPU百分比(注意多核服务器可能超过100%)
TIME+:进程累计使用的CPU时间
S列(状态):R(运行中)或D(不可中断睡眠,通常在等I/O)
使用htop(如果已安装)
htop
# 更直观的界面,彩色显示,支持鼠标操作
# F5: 树状显示进程关系
# F6: 选择排序字段
# F9: 杀死进程

使用ps命令快速抓取
# 获取CPU占用TOP10的进程
ps aux | head -1; ps aux | sort -rn -k3 | head -10
# 查看某个用户的所有进程
ps -u test -o pid,ppid,%cpu,%mem,cmd --sort=-%cpu | head -20
检测的shell脚本参考
#!/bin/bash
# cpu_quick_check.sh - 快速CPU诊断脚本
echo"========== CPU整体状态 =========="
uptime
echo""
echo"========== CPU详细使用率 =========="
top -bn1 | head -20
echo""
echo"========== CPU占用TOP10进程 =========="
ps aux --sort=-%cpu | head -11
echo""
echo"========== 当前CPU核心数 =========="
grep -c processor /proc/cpuinfo
echo""
echo"========== 负载均衡情况 =========="
mpstat -P ALL 1 1
准定位到具体线程和代码
查看进程内的线程CPU占用
# 方法1: 使用top查看线程
top -H -p <PID>
# -H: 显示线程模式
# -p: 指定进程ID
# 方法2: 使用ps查看线程
ps -Lp <PID> -o pid,lwp,ppid,pcpu,comm --sort=-pcpu | head -20
# -L: 显示线程
# lwp: 线程ID
#记录CPU占用最高的线程ID(LWP),并转换为16进制(因为堆栈信息中线程ID是16进制)
# 假设线程ID为12345
printf"0x%x\n" 12345
# 输出: 0x3039
Java应用定位到具体代码
# 1. 找到高CPU线程ID
top -H -p <Java进程PID>
# 假设找到线程ID 12345
# 2. 转换为16进制
printf"0x%x\n" 12345 # 得到 0x3039
# 3. 导出Java线程堆栈
jstack <Java进程PID> > /tmp/jstack.log
# 4. 在堆栈文件中搜索该线程
grep -A 20 "0x3039" /tmp/jstack.log
# 一键脚本
show_java_high_cpu_thread() {
local pid=$1
local thread_id=$(top -bn1 -H -p $pid | grep -v PID | sort -rn -k9 | head -1 | awk '{print $1}')
local hex_tid=$(printf"0x%x"$thread_id)
echo"High CPU Thread ID: $thread_id ($hex_tid)"
jstack $pid | grep -A 30 "$hex_tid"
}
# 使用: show_java_high_cpu_thread <PID>
Python应用定位
# 使用py-spy(需提前安装: pip install py-spy)
py-spy top --pid <PID>
# 查看火焰图
py-spy record -o profile.svg --pid <PID> --duration 30
# 使用gdb(如果py-spy不可用)
gdb -p <PID>
(gdb) py-bt
(gdb) thread apply all py-list
Node.js应用
# 1. 发送SIGUSR1信号生成CPU profile
kill -USR1 <PID>
# 2. 使用内置profiler
node --prof app.js
# 停止后会生成isolate-xxx-v8.log文件
node --prof-process isolate-xxx-v8.log > processed.txt
# 3. 使用clinic.js(更友好的工具)
npm install -g clinic
clinic doctor -- node app.js
Go应用定位
# 如果应用开启了pprof(通常在代码中引入了net/http/pprof)
# 查看CPU profile
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
# 进入交互式界面后:
(pprof) top 10 # 查看CPU占用前10的函数
(pprof) list <function_name> # 查看具体函数代码
(pprof) web # 生成可视化图表(需安装graphviz)
C/C++应用定位
# 使用perf工具(最强大的Linux性能分析工具)
# 1. 记录30秒的CPU采样
perf record -p <PID> -g -- sleep 30
# 2. 查看报告
perf report
# 3. 生成火焰图(需要FlameGraph工具)
perf script | stackcollapse-perf.pl | flamegraph.pl > flame.svg
有些情况下,CPU高占用并非应用代码问题,而是系统级资源瓶颈导致
检查I/O等待,
-
如果
%wa (iowait)高(>20%),且%util接近100%,说明是磁盘I/O瓶颈 -
• 优化方向:检查是否有大量日志写入、数据库查询未命中索引、大文件操作等
# 查看I/O等待时间
iostat -x 1 5
# 关键指标:
# %util: 接近100%说明磁盘已饱和
# await: 平均等待时间,SSD应<5ms,机械盘应<20ms
# r/s, w/s: 每秒读写次数
# 查看哪些进程在等待I/O
pidstat -d 1 5
# 查看具体文件操作
iotop -o # 只显示有I/O操作的进程
检查网络软中断
-
如果
%si (software interrupt)高(>10%),通常是网络流量大 -
• 常见原因:DDoS攻击、大量短连接、网络包处理不合理
# 查看软中断统计
cat /proc/softirqs
# 持续观察软中断变化
watch -d "cat /proc/softirqs | head -20"
# 查看网络流量
iftop -i eth0
# 或者
nload eth0
# 查看网络连接数
netstat -antp | wc -l
ss -s # 显示socket统计
检查进程创建销毁频率
-
如果
%sy (system CPU)高(>30%),可能是系统调用过多 -
• 常见原因:CGI程序每次都fork新进程、shell脚本大量调用外部命令
# 查看进程创建速率
pidstat 1 5
# 查看系统调用统计
strace -c -p <PID>
# 查看fork/exec调用频率
perf stat -e 'syscalls:sys_enter_*' -a sleep 10 | grep -E "(fork|exec|clone)"
检查上下文切换
-
上下文切换>100万次/秒,可能存在性能问题
-
• 非自愿切换过多,说明进程/线程数过多,CPU调度压力大
# 查看上下文切换频率
vmstat 1 5
# 关注 cs (context switch) 列
# 查看每个进程的上下文切换
pidstat -w 1 5
# cswch/s: 自愿上下文切换(主动让出CPU)
# nvcswch/s: 非自愿上下文切换(被强制切换)
检查内存压力
-
如果内存不足导致频繁swap,CPU会消耗在内存页换入换出上
-
• MemAvailable < 10%总内存,且swap使用率高,需要关注
# 查看内存使用情况
free -h
# 查看内存详细信息
cat /proc/meminfo | grep -E "(MemTotal|MemFree|MemAvailable|SwapTotal|SwapFree)"
# 查看是否有OOM killer
dmesg | grep -i "out of memory"
grep -i "out of memory" /var/log/messages
# 查看内存分配
slabtop
综合诊断命令
# 使用dstat综合查看(需安装)
dstat -tcmndylsp --top-cpu --top-mem 5
# 使用sar(系统活动报告)
sar -u 1 10 # CPU使用率
sar -q 1 10 # 负载和运行队列
sar -w 1 10 # 上下文切换
# 一键生成诊断报告
(
echo"=== System Load ==="
uptime
echo""
echo"=== CPU Stats ==="
mpstat -P ALL 1 1
echo""
echo"=== Memory Stats ==="
free -h
echo""
echo"=== I/O Stats ==="
iostat -x 1 1
echo""
echo"=== Network Stats ==="
ss -s
echo""
echo"=== Top Processes ==="
ps aux --sort=-%cpu | head -20
) | tee cpu_diagnosis_$(date +%Y%m%d_%H%M%S).txt
更多推荐

所有评论(0)