别再只会用 top 了!这 5 个 Linux 性能排查命令才是救命稻草
一、问题背景
线上系统出问题时,90% 的初中级运维第一时间想到的就是 top。但 top 只能告诉你 CPU 占用高的几个进程、内存总量使用率,至于"为什么 CPU 高"、“为什么 IO 高”、“为什么网卡跑满了”、“为什么系统慢但 CPU 不高”,top 给不了答案。
真实的故障排查场景:
- 应用突然变慢,top 看 CPU 不到 10%,IO 也正常,但接口 P99 涨了 10 倍
- 数据库响应慢,但磁盘 IO util 不到 30%
这些场景必须用更专业的工具才能定位:vmstat 看系统级整体指标,mpstat/pidstat 看每个 CPU 和每个进程的统计,iostat 看磁盘 IO,sar 看历史,perf/bpftrace 看内核热点。
这一篇不讲虚的,全部围绕"现象 → 命令 → 输出 → 判断 → 修复 → 验证 → 回滚"展开,把 5 个真正救命的命令讲透。
二、适用场景
三、核心知识点
3.1 性能排查的五个层次
性能问题可以从五个层次看:
- 系统级(system-wide):vmstat、mpstat、sar
- 进程级(per-process):pidstat、top、ps
3.2 性能排查常用方法论
USE 方法(Brendan Gregg):
对每个资源(CPU、内存、磁盘、网络)依次看 USE 三个指标。
3.3 5 个救命命令清单
- vmstat:系统整体状态(CPU、内存、IO、system)
- pidstat:每个进程的 CPU/内存/IO/上下文切换
再加上 top 作为补充,每个命令各司其职。
3.4 何时用哪个命令
3.5 关键性能指标
CPU:
- wa(iowait):等待 IO 的 CPU 时间
内存:
IO:
- svctm:单次 IO 服务时间(已废弃,参考 util)
进程:
四、整体排查或实施思路
性能排查按层次往下走:
- 系统层:vmstat 1 看 CPU/IO/内存整体
- CPU 层:mpstat -P ALL 1 看每核负载
- 进程层:pidstat -u -r -d 1 看每个进程
每一步都能确认或排除一类根因。
排查套路:
- CPU 高:vmstat 看 us/sy → mpstat 看单核 → pidstat 看进程 → perf 看热点
- IO 高:vmstat 看 wa/bi/bo → iostat 看设备 → pidstat -d 看进程 → iotop 实时
- 内存高:vmstat 看 si/so/free → pidstat -r 看进程 RSS → smem 看真实占用
- 网络高:sar -n DEV 看流量 → nicstat 看包量 → ss 看连接 → tcpdump 抓包
五、实战步骤
5.1 现象:应用响应慢,top 看 CPU 不高
5.1.1 初步判断
top -bn1 | head -20uptime
预期输出:
top - 16:00:00 up 100 days, 1 user, load average: 8.00, 8.00, 8.00
判断:load average 高(>CPU 核数)但 top 看 CPU% 不高 → 大概率 IO 阻塞。
5.1.2 命令检查
预期输出:
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 1 8 0 1024000 204800 4096000 0 0 0 100 1000 2000 5 3 10 82 0
判断:
- bi/bo 不一定高,但 b 高说明 IO 队列长
5.1.3 关键指标
5.1.4 根因定位
预期输出:
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %utilsda 0 0 0 50 0 400 16.0 32.0 640.0 0.0 640.0 0.5 100.00
判断:
- avgqu-sz = 32:队列 32 个 IO 在等
根因:磁盘 IO 已经饱和,可能是数据库在做大量随机写。
5.1.5 修复
5.1.6 验证
预期:b 列降低、wa 降低。
5.1.7 回滚
如果优化导致问题,恢复原配置:数据库参数、磁盘挂载、业务流量调度。
5.2 现象:CPU 单核跑满,其他核闲着
5.2.1 初步判断
判断:单核 100%,其他核 0%,大概率是单线程应用。
5.2.2 命令检查
预期输出:
16:00:00 CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle16:00:01 all 6.25 0.00 3.12 0.00 0.00 0.00 0.00 0.00 0.00 90.6216:00:01 0 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.0016:00:01 1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
判断:CPU 0 跑满,其他空闲。
5.2.3 进程定位
预期输出:
16:00:00 UID PID %usr %system %guest %wait %CPU CPU Command16:00:01 1001 1234 99.00 1.00 0.00 0.00 100.00 0 myapp
5.2.4 根因
单线程应用(典型的 Python、PHP、老 JVM)。
5.2.5 修复
5.2.6 验证
判断:多核负载均衡。
5.3 现象:内存使用率高,但应用不大
5.3.1 初步判断
预期:
total used free shared buff/cache availableMem: 16Gi 15Gi 500Mi 100Mi 500Mi 800MiSwap: 8.0Gi 200Mi 7.8Gi
判断:used 看起来 15Gi,但 available 只有 800Mi。说明 buff/cache 没贡献。
5.3.2 进程占用
预期:
16:00:00 UID PID minflt/s majflt/s VSZ RSS %MEM Command16:00:01 1001 1234 0.00 0.00 4.0G 2.0G 12.50 myapp
5.3.3 真实占用
ps -o pid,user,rss,vsz,comm -p <pid>smem -p -P myapp
判断:smem 能给出 USS(独占)/PSS(按比例)/RSS。
5.3.4 根因
5.3.5 修复
- 泄漏:heap dump、jmap、pympler
5.3.6 验证
5.4 现象:磁盘 IO 抖动,await 波动
5.4.1 命令检查
判断:
5.4.2 进程级
预期:
16:00:00 UID PID kB_rd/s kB_wr/s kB_ccwr/s iodelay Command16:00:01 1001 1234 0.00 1024.00 0.00 5 myapp
5.4.3 实时
判断:能实时看到哪个进程在写盘。
5.4.4 根因
5.4.5 修复
5.4.6 验证
5.5 现象:网络延迟高,带宽没满
5.5.1 流量
预期:
16:00:00 IFACE rxpck/s txpck/s rxkB/s txkB/s %ifutil16:00:01 eth0 500.00 400.00 50.00 30.00 5.00
判断:流量不大,但延迟高。
5.5.2 包量与丢包
预期:
16:00:00 IFACE rxerr/s txerr/s rxdrop/s txdrop/s16:00:01 eth0 0.00 0.00 50.00 0.00
判断:rxdrop=50,网卡在丢包,可能是 ring buffer 不够。
5.5.3 查看连接
ss -sss -tan | awk '{print $1}' | sort | uniq -c
5.5.4 根因
5.5.5 修复
- 加大 ring buffer:ethtool -G
5.5.6 验证
5.6 现象:sar 看历史性能,回溯事故
5.6.1 看 CPU 历史
sar -u -f /var/log/sa/sa25
5.6.2 看内存历史
sar -r -f /var/log/sa/sa25
5.6.3 看 IO 历史
sar -b -f /var/log/sa/sa25sar -d -f /var/log/sa/sa25
5.6.4 看网络历史
sar -n DEV -f /var/log/sa/sa25
5.6.5 看负载历史
sar -q -f /var/log/sa/sa25
5.6.6 看 swap 历史
sar -S -f /var/log/sa/sa25
5.6.7 看 runq 历史
sar -W -f /var/log/sa/sa25
判断:sar 的 -f 选项能加载历史数据,是事后复盘的利器。
5.7 现象:上下文切换高
5.7.1 命令检查
判断:cs 列 > 100k/s 偏高。
5.7.2 进程级
预期:
16:00:00 UID PID cswch/s nvcswch/s Command16:00:01 1001 1234 5000.00 100.00 myapp
判断:cswch 高说明进程在主动让出 CPU(等锁、等 IO)。
5.7.3 根因
5.7.4 修复
5.8 现象:软中断高
5.8.1 命令检查
判断:%soft 列高。
5.8.2 看哪个 CPU
判断:某几个核 %soft 高,多队列网卡绑核不均。
5.8.3 修复
- 多队列绑核:IRQBALANCE_BANNED_CPUS
5.9 现象:perf 看热点
5.9.1 实时采样
5.9.2 记录
perf record -F 99 -a -g -- sleep 30perf report --stdio
5.9.3 看调用栈
判断:能看到哪个内核函数被调用最多。
5.10 现象:bpftrace 看内核 trace
5.10.1 安装
5.10.2 抓 IO 延迟
bpftrace -e 'kprobe:blk_mq_start_request { @start[arg0] = nsecs; } kprobe:blk_mq_end_request /@start[arg0]/ { @usecs = hist((nsecs - @start[arg0]) / 1000); delete(@start[arg0]); }'
判断:直方图看 IO 延迟分布。
5.10.3 抓 TCP 重传
bpftrace -e 'kprobe:tcp_retransmit_skb { @retrans++; }'
六、常用命令
6.1 vmstat
vmstat 1 # 每秒输出一次vmstat 1 10 # 输出 10 次vmstat -s # 一次性输出所有累计指标vmstat -d # 磁盘统计vmstat -p /dev/sda1 # 指定分区
判断:第一行通常被忽略(自启动以来的平均值),从第二行开始看。
6.2 mpstat
mpstat 1 # 全部 CPU 平均mpstat -P ALL 1 # 每核mpstat -P 0 1 # CPU 0mpstat -u 1 # CPU 利用率
判断:%iowait > 30% 通常有 IO 瓶颈;%soft 高说明网络或块设备软中断多。
6.3 pidstat
pidstat 1 # 全部进程pidstat -p 1234 1 # 指定进程pidstat -u 1 # CPUpidstat -r 1 # 内存pidstat -d 1 # IOpidstat -w 1 # 上下文切换pidstat -t 1 # 线程
判断:pidstat 比 top 多两个能力:能看到进程在哪个 CPU、能看到 kB_rd/s 和 kB_wr/s。
6.4 iostat
iostat -xz 1 # 扩展统计,每秒iostat -d 1 # 磁盘统计iostat -p sda 1 # 指定磁盘iostat -m 1 # MB/siostat -N 1 # LVM 设备
判断:%util > 80% 持续 5 分钟通常有 IO 瓶颈。
6.5 sar
sar 1 5 # 全部基础指标sar -u 1 5 # CPUsar -r 1 5 # 内存sar -b 1 5 # IOsar -d 1 5 # 每块设备sar -n DEV 1 5 # 网络流量sar -n EDEV 1 5 # 网络错误sar -n TCP 1 5 # TCPsar -q 1 5 # 负载sar -S 1 5 # swapsar -W 1 5 # swap 换入sar -A # 全部sar -f /var/log/sa/sa25 # 历史数据
判断:sar 数据采集器是 sadc,需要 sysstat 包,默认每 10 分钟采一次,保留 7 天。
6.6 top
top -bn1 # 静态输出top -p 1234 # 指定进程top -H # 线程top -c # 显示命令行top -o %CPU # 按 CPU 排序top -o %MEM # 按内存排序top -u myapp # 指定用户
判断:top 适合快速浏览,不适合写监控。
6.7 其他常用工具
htopiotopiftopnethogssslsofpstreeperfbpftracesmemnumastat
6.8 sysstat 安装与配置
yum install sysstatsystemctl enable sysstatsystemctl start sysstat
# /etc/sysconfig/sysstatHISTORY=28COMPRESSAFTER=14SADC_OPTIONS="-S DISK"
6.9 cron 自动采集
# /etc/cron.d/sysstat*/10 * * * * root /usr/lib64/sa/sa1 1 153 23 * * * root /usr/lib64/sa/sa2 -A
判断:sa1 是采样、sa2 是日终汇总。
七、配置示例
7.1 /etc/sysconfig/sysstat
HISTORY=28COMPRESSAFTER=14SADC_OPTIONS="-S DISK"
判断:保留 28 天,14 天后压缩。
7.2 /etc/cron.d/sysstat
*/10 * * * * root /usr/lib64/sa/sa1 1 153 23 * * * root /usr/lib64/sa/sa2 -A
判断:每 10 分钟采样,每晚 23:53 汇总。
7.3 prometheus node_exporter 文本采集配置
scrape_configs:-job_name:'node'static_configs:-targets: ['node_exporter:9100']scrape_interval:15s
判断:node_exporter 默认会暴露 sysstat 数据。
7.4 Grafana 面板变量
$instance: 主机名$cpu: cpu 编号$device: 磁盘设备$nic: 网卡名
判断:panel 变量化便于跨主机对比。
7.5 告警规则示例(Prometheus)
groups:-name:cpurules:-alert:HighCpuLoadexpr:100-(avgby(instance)(rate(node_cpu_seconds_total{mode="idle"}[5m]))*100)>80for:10mannotations:summary:"CPU > 80% on {{ $labels.instance }}"
判断:阈值要结合业务基线,不要硬编码。
7.6 慢查询阈值配置(MySQL)
slow_query_log = 1long_query_time = 1log_slow_extra = ON
判断:long_query_time 单位是秒。
7.7 perf 配置
# /proc/sys/kernel/perf_event_paranoid-1 # 允许所有用户使用 perf0 # 允许普通用户采样 CPU 事件1 # 只允许 root2 # 默认,只允许 CPU events3 # 完全禁用
判断:生产环境建议 2 或 1。
7.8 sysctl 性能参数
# /etc/sysctl.d/99-performance.confnet.core.somaxconn = 65535net.core.netdev_max_backlog = 65535net.ipv4.tcp_max_syn_backlog = 65535net.ipv4.tcp_tw_reuse = 1net.ipv4.tcp_fin_timeout = 15vm.swappiness = 10vm.dirty_ratio = 15vm.dirty_background_ratio = 5fs.file-max = 200000fs.nr_open = 200000
判断:性能调优要结合业务测试。
7.9 iostat 阈值监控脚本
#!/bin/bashwhiletrue; do await=$(iostat -xz 1 2 | tail -1 | awk '{print $11}') util=$(iostat -xz 1 2 | tail -1 | awk '{print $NF}')if (( $(echo "$await > 50" | bc -l) )) || (( $(echo "$util > 80" | bc -l) )); thenecho"ALERT: await=$await util=$util"fisleep 5done
判断:阈值需要根据基线调整。
7.10 上下文切换阈值监控
#!/bin/bashcs=$(vmstat 1 2 | tail -1 | awk '{print $12}')if [ "$cs" -gt 100000 ]; thenecho"ALERT: context switch=$cs/s"fi
判断:>100k/s 偏高,>500k/s 严重。
八、日志或指标观察方法
8.1 关键性能指标列表
| | |
|---|
| | |
| used/free/buff/cache/swap | |
| | |
| | |
| | |
| | |
| | |
| | |
8.2 阈值经验值(需结合业务基线调整)
8.3 指标采集间隔
8.4 关联分析
性能问题往往不是单点。分析思路:
- CPU 高 + sy 高 = 内核瓶颈(锁、syscall)
- 内存 high + swap > 0 = 内存不够
- await 高 + %util 低 = 队列问题(NVMe 多队列、SSD 控制器)
8.5 慢 IO 排查流程
iostat -xz 1 5 # 整体 IOiotop -ao # 实时进程pidstat -d 1 # 进程 IO 速率iotop -P # 累计 IObpftrace IO trace # 内核 trace
8.6 网络瓶颈排查流程
sar -n DEV 1 5 # 流量sar -n EDEV 1 5 # 错误nicstat 1 5 # 详细ss -s # socket 统计ss -tan # 连接tcpdump -i eth0 -w # 抓包
8.7 内存瓶颈排查流程
free -h # 总体vmstat 1 5 # 系统pidstat -r 1 # 进程 RSSsmem -p -P myapp # 真实占用slabtop # 内核 slabcat /proc/meminfo # 详细
8.8 CPU 瓶颈排查流程
top -bn1 # 概览mpstat -P ALL 1 # 每核pidstat -u 1 # 进程 CPUperf top # 内核热点strace -c -p <pid> # syscall
8.9 火焰图
yum install perfperf record -F 99 -a -g -- sleep 30perf script | ./stackcollapse-perf.pl | ./flamegraph.pl > flame.svg
判断:火焰图能直观看出热点函数。
8.10 性能数据归档
#!/bin/bashDATE=$(date +%Y%m%d)mkdir -p /var/perf-archive/$DATEsar -A > /var/perf-archive/$DATE/sar.txtvmstat 1 60 > /var/perf-archive/$DATE/vmstat.txtmpstat -P ALL 1 60 > /var/perf-archive/$DATE/mpstat.txtiostat -xz 1 60 > /var/perf-archive/$DATE/iostat.txtpidstat -u -r -d 1 60 > /var/perf-archive/$DATE/pidstat.txt
判断:归档保留 ≥ 90 天,便于长期复盘。
九、排查路径
9.1 “应用慢”
9.2 “数据库慢”
- SHOW ENGINE INNODB STATUS
9.3 “网络慢”
9.4 “内存慢”
9.5 “磁盘慢”
十、风险提醒
kill -9 <pid>echo 3 > /proc/sys/vm/drop_caches:仅释放 buff/cache,不影响业务,但生产慎用sysctl -pperf record -a -gbpftracedd if=/dev/zero of=/data/test bs=1G count=10stress --cpu 8kill -STOP <pid>tc qdisc add dev eth0 root netem delay 1000msiperf3 -c serversmartctl --smart-testhdparm -Tt /dev/sdafio --rw=randwritetcpdump -i anyperf stat -e cache-missessysctl vm.swappiness=0chmod -R 777 /proc/sys/vmecho c > /proc/sysrq-trigger
十一、验证方式
十二、回滚方案
12.1 sysctl 回滚
# 1. 备份cp /etc/sysctl.d/99-custom.conf /etc/sysctl.d/99-custom.conf.bak# 2. 改回原值vi /etc/sysctl.d/99-custom.conf# 3. 重载sysctl -p /etc/sysctl.d/99-custom.conf
12.2 进程回滚
# 1. 停止当前进程systemctl stop myapp# 2. 切回旧版本ln -sfn /opt/myapp-1.0 /opt/myapp-current# 3. 启动systemctl start myapp
12.3 数据库参数回滚
SETGLOBAL innodb_buffer_pool_size =4*1024*1024*1024;
或重启加载旧 my.cnf。
12.4 内核参数回滚
# 把内核参数恢复原值sysctl net.core.somaxconn=128
12.5 配置文件回滚
cp /etc/my.cnf.bak /etc/my.cnfsystemctl restart mysqld
12.6 磁盘 IO 调优回滚
# 改回默认调度器echo cfq > /sys/block/sda/queue/scheduler
12.7 网络参数回滚
tc qdisc del dev eth0 rootethtool -G eth0 rx 256 tx 256
12.8 服务重启回滚
# 1. 先恢复配置cp /etc/myapp/myapp.conf.bak /etc/myapp/myapp.conf# 2. 重启服务systemctl restart myapp
12.9 内核升级回滚
dnf remove kernel-5.14.0-newgrub2-mkconfig -o /boot/grub2/grub.cfgreboot
12.10 完整回滚检查清单
十三、生产环境注意事项
十四、总结
top 是入门,但只靠 top 救不了线上问题。这 5 个命令各司其职:
加上 perf 和 bpftrace 等工具,可以应对 90% 的性能问题。
性能排查的思路:先系统后进程,先 CPU 后 IO,先实时后历史。
记住一句话:性能问题不是单点出现的,定位时要把多个指标关联起来看,不要只盯一个数字。
十五、性能排查的 12 条经验
- 先看整体后看个体
- 先看实时后看历史
- 先看 CPU 后看 IO
- 先看资源后看应用
- 先看进程后看线程
- 先看内核后看用户
- 先看频率后看带宽
- 先看数量后看延迟
- 先看趋势后看峰值
- 先看对比后看绝对
- 先看基线后看异常
- 先看慢再查快
十六、性能调优速查表
十七、与其他工具的协作
17.1 vmstat + dstat
判断:dstat 是 vmstat 的增强版,更直观。
17.2 iostat + iotop
判断:iotop 实时,iostat 平均。
17.3 mpstat + perf
mpstat -P ALL 1perf top -C 0
判断:mpstat 看 CPU 0 忙,perf 看 CPU 0 上的函数。
17.4 pidstat + pstree
pidstat -u 1pstree -p <pid>
判断:pidstat 看哪个进程,pstree 看进程关系。
17.5 sar + grafana
sar 数据采集,grafana 展示。
17.6 perf + bpftrace
perf 适合采样,bpftrace 适合单点 trace。
十八、性能监控设计建议
18.1 监控分层
18.2 采集频率
18.3 存储周期
18.4 告警分级
18.5 告警收敛
多个告警关联到一个根因。
18.6 告警疲劳避免
阈值要基于基线,不要硬编码。
18.7 告警演练
每月做一次告警演练。
十九、性能基线示例
19.1 主机基线
19.2 数据库基线
19.3 应用基线
二十、容器场景的性能排查
20.1 容器内的 vmstat
docker exec <container> vmstat 1
20.2 看容器 cgroup
cat /sys/fs/cgroup/cpu/system.slice/docker-<id>.scope/cpuacct.usage
20.3 看容器 IO
cat /sys/fs/cgroup/blkio/system.slice/docker-<id>.scope/blkio.throttle.io_service_bytes
20.4 容器内 perf
容器内 perf 需要 --cap-add=SYS_PTRACE 或特权模式。
20.5 Kubernetes 中的性能排查
kubectl top pod <pod>kubectl top node <node>kubectl describe pod <pod>
判断:kubectl top 依赖 metrics-server。
二十一、压测工具推荐
- fio
- iperf3
- sysbench
- wrk
- ab
- stress-ng
- netperf
- dd
二十二、案例:一次完整的性能故障复盘
22.1 故障发生
业务反馈:下午 3 点开始,应用 P99 延迟从 50ms 涨到 800ms。
22.2 初步判断
看到 %CPU 不高,但 load average 12(机器 8 核)。
load average: 12.00, 10.00, 8.00
判断:CPU 负载高,但 CPU% 不高,IO 阻塞嫌疑。
22.3 命令检查
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 1 8 0 1024000 204800 4096000 0 0 10 200 1000 2000 5 3 10 82 0
判断:b=8,wa=82%,确认是 IO 阻塞。
22.4 定位设备
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %utilsda 0 0 0 50 0 400 16.0 32.0 640.0 0.0 640.0 0.5 100.00sdb 0 0 0 10 0 80 16.0 1.0 12.0 0.0 12.0 0.5 5.00
判断:sda 满载,await 640ms。
22.5 定位进程
16:00:00 UID PID kB_rd/s kB_wr/s kB_ccwr/s iodelay Command16:00:01 1001 1234 0.00 2048.00 0.00 5 myapp
判断:myapp 进程在大量写盘。
22.6 根因
myapp 在写大量 debug 日志到 sda,sda 是 SSD 但容量已满 80%,IO 抖动。
22.7 修复
22.8 验证
判断:sda 负载降回基线,wait 归零。
22.9 复盘
二十三、运维手册:性能排查 checklist
每次性能问题按这个走:
- 收集:uptime、top、vmstat 1 5、mpstat -P ALL 1 3、iostat -xz 1 3
二十四、写在最后
性能排查是运维的核心技能之一。top 只是起点,vmstat、mpstat、pidstat、iostat、sar 才是真正能救命的工具。把这一篇收藏好,遇到性能问题按章节走,把每个命令都跑熟。
记住:性能问题不是单点的,要看多个指标的关联;性能调优是持续的过程,不是一次性的工作。
把 5 个命令练熟,比看 100 篇科普文有用。
二十五、NUMA 架构下的性能排查
25.1 NUMA 简介
现代多路服务器采用 NUMA(Non-Uniform Memory Access)架构。每个 CPU 有自己的本地内存,访问其他 CPU 的内存要跨 socket。
25.2 看 NUMA 拓扑
numactl --hardwarelscpu | grep NUMA
预期输出:
available: 2 nodes (0-1)node 0 cpus: 0 1 2 3 4 5 6 7node 0 size: 32768 MBnode 0 free: 16384 MBnode 1 cpus: 8 9 10 11 12 13 14 15node 1 size: 32768 MBnode 1 free: 16384 MBnode distances:node 0 1 0: 10 20 1: 20 10
判断:跨 node 访问距离 20,本地访问 10。
25.3 看 NUMA 内存分布
预期输出:
Per-node process memory usage (in MBs) for PID 1234 (myapp) Node 0 Node 1 Total ------ ------ -----Heap 512 128 640Stack 8 8 16Private 256 512 768------- --- --- -----Total 776 648 1424
判断:如果分配不均,说明进程被绑在某个 node。
25.4 NUMA 不均的后果
25.5 修复
- 进程绑核:numactl --cpunodebind=0 --membind=0
- 内核自动平衡:sysctl vm.zone_reclaim_mode
- 禁用自动平衡:sysctl kernel.numa_balancing=0
25.6 验证
numastat -p <pid>perf stat -e node-loads,node-load-misses -p <pid>
判断:node-load-misses 接近 0 表示 NUMA 友好。
二十六、cgroup 资源隔离性能
26.1 看 cgroup CPU
cat /sys/fs/cgroup/cpu/system.slice/docker-<id>.scope/cpuacct.usage
判断:cgroup CPU 限速会让进程在内核态看到限速。
26.2 cgroup CPU 限制配置
# docker-compose.ymlservices:myapp:image:myapp:1.0cpus:"2.0"mem_limit:4g
26.3 cgroup v2 性能
cgroup v2 在多核、IO 控制上更精细,建议生产环境使用。
26.4 systemd slice 性能
[Slice]CPUQuota=200%MemoryMax=4GIOWeight=100
二十七、内核调度器性能
27.1 查看当前调度器
cat /sys/block/sda/queue/scheduler
预期:
27.2 各调度器适用场景
27.3 切换调度器
echo deadline > /sys/block/sda/queue/scheduler
27.4 验证
判断:await 降低为正常。
27.5 多队列 NVMe
NVMe 默认有多个 submission queue,可以看:
cat /sys/block/nvme0n1/queue/nr_requests
二十八、内核参数调优示例
28.1 TCP 性能
net.ipv4.tcp_congestion_control = bbrnet.core.default_qdisc = fqnet.ipv4.tcp_fastopen = 3net.ipv4.tcp_slow_start_after_idle = 0net.ipv4.tcp_mtu_probing = 1
28.2 BBR 验证
sysctl net.ipv4.tcp_congestion_controliperf3 -c <server>
判断:BBR 在长肥管道下能提升 2-10 倍。
28.3 文件描述符
fs.file-max = 2000000fs.nr_open = 2000000
28.4 进程数
28.5 内存
vm.swappiness = 10vm.dirty_ratio = 15vm.dirty_background_ratio = 5vm.dirty_expire_centisecs = 1500vm.dirty_writeback_centisecs = 500
28.6 验证
sysctl -p /etc/sysctl.d/99-custom.confsysctl net.ipv4.tcp_congestion_control
二十九、CPU 性能模式
29.1 cpufreq 模式
cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
预期:
或:
29.2 切换性能模式
cpupower frequency-set -g performance
29.3 节能模式
cpupower frequency-set -g powersave
判断:服务器场景一般用 performance,桌面用 ondemand 或 schedutil。
29.4 关闭超线程
echo 0 > /sys/devices/system/cpu/cpu1/online
判断:某些负载下超线程反而拖慢性能。
29.5 turbo boost
cat /sys/devices/system/cpu/intel_pstate/no_turbo
判断:1 表示关闭 turbo,0 表示开启。
三十、内存性能
30.1 大页
sysctl vm.nr_hugepages = 1024cat /proc/meminfo | grep Huge
30.2 透明大页
cat /sys/kernel/mm/transparent_hugepage/enabled
判断:[always] 表示开启,[never] 表示关闭。
30.3 NUMA 平衡
sysctl kernel.numa_balancing = 1
判断:自动 NUMA 平衡有性能开销。
30.4 swap 性能
cat /proc/sys/vm/swappiness
判断:数据库服务器建议 1-10,普通应用 30-60。
30.5 OOM 行为
sysctl vm.panic_on_oom = 0sysctl vm.oom_kill_allocating_task = 0
判断:0 表示由内核选进程 kill,1 表示只 kill 分配内存的进程。
三十一、磁盘 IO 性能
31.1 read_ahead 调整
blockdev --setra 4096 /dev/sda
判断:顺序读多的场景调大,随机读场景调小。
31.2 队列深度
cat /sys/block/sda/queue/nr_requests
判断:NVMe 通常 1024+,SATA SSD 31。
31.3 IO 调度器
echo none > /sys/block/nvme0n1/queue/scheduler
31.4 文件系统
31.5 mount 选项
mount -o noatime,nodiratime,discard /dev/sda1 /data
判断:noatime 减少 atime 更新,nodiratime 减少目录 atime。
三十二、CPU 亲和性
32.1 看 CPU 亲和
预期:
current affinity mask: ff
判断:ff 表示 8 个核都在允许集。
32.2 绑核
taskset -pc 0,2,4,6 <pid>
32.3 启动时绑核
numactl --physcpubind=0-7 --membind=0 /usr/local/bin/myapp
32.4 systemd 绑核
[Service]CPUAffinity=0123
三十三、压力测试
33.1 CPU 压测
stress-ng --cpu 8 --timeout 60s
判断:用于复现 CPU 满载问题。
33.2 内存压测
stress-ng --vm 1 --vm-bytes 8G --timeout 60s
33.3 IO 压测
fio --name=randwrite --ioengine=libaio --direct=1 --filename=/data/test --bs=4k --size=1G --rw=randwrite --numjobs=4
33.4 网络压测
iperf3 -c <server> -P 4 -t 30
33.5 数据库压测
sysbench /usr/share/sysbench/oltp_read_only.lua --mysql-host=127.0.0.1 --mysql-user=root --mysql-password=xxx --mysql-db=sbtest --tables=10 --table-size=1000000 --threads=16 preparesysbench /usr/share/sysbench/oltp_read_only.lua --threads=16 --time=60 --report-interval=10 run
三十四、生产环境压测注意事项
三十五、案例:某电商大促性能优化
35.1 背景
大促前发现应用响应慢,预计大促会有 10 倍流量。
35.2 排查
35.3 根因
35.4 优化
35.5 验证
35.6 复盘
三十六、与监控告警的整合
36.1 关键指标告警
-alert:HighCpuIowaitexpr:avgby(instance)(rate(node_cpu_seconds_total{mode="iowait"}[5m]))*100>20for:10mannotations:summary:"CPU iowait > 20% on {{ $labels.instance }}"-alert:HighDiskUtilexpr:100-(avgby(instance)(rate(node_filesystem_free_bytes{fstype!~"tmpfs|overlay"}[5m]))*100)>80for:10m
36.2 复合指标
36.3 性能告警
延迟告警比资源告警更直接:
-alert:HighResponseTimeexpr:histogram_quantile(0.99,sumby(le)(rate(http_request_duration_seconds_bucket[5m])))>1for:5m
判断:业务指标比资源指标更敏感。
三十七、本文速记口诀
性能问题排查:
按顺序跑,先系统后进程,先 CPU 后 IO,先实时后历史。
三十八、推荐阅读
- Brendan Gregg 《Systems Performance》
- Brendan Gregg 博客 http://www.brendangregg.com/
- Linux Performance 文档 http://www.brendangregg.com/linuxperf.html
三十九、最后的最后
性能排查没有银弹,只有方法论和工具的结合。把这一篇的 5 个命令练熟,遇到性能问题按章节走,再结合业务场景做判断,比临时百度高效得多。
性能优化是持续的过程,不是一蹴而就。建立基线、持续监控、定期复盘,是把性能做好的三把钥匙。