0. 写在前面:为什么你需要“神器”而非“常用命令
把系统从「慢」变成「稳」有时候不需要大折腾,而是把最显著的瓶颈找出来。下面是一套我常用的方法.
先说一句话的心法:先把用户感受恢复,再去追根溯源。很多时候临时的减害手段(降级、限流、回滚、切流)比立刻找根因更重要。下面分三类瓶颈:CPU、内存、IO(含磁盘与网络),每类给出诊断命令、常见判别依据、应急缓解和长期修复建议。
这些命令几乎是现场救火的工具箱,建议熟练掌握:
top, htop, vmstat, mpstat, pidstat, ps, perf, strace, pstack
free, slabtop, smem
iostat, iotop, blktrace, lsblk, df, du, smartctl
ss, netstat, iftop, iperf3, tc
sar (sysstat), dstat, atop
tcpdump (小心会产生日志)
我常把一台机器的检查脚本写成几行命令串,先快速跑一遍,得出第一轮结论,再深入。
看整体负载(load)只是起点,关键是区分:是用户态占满、内核态占满、还是等待 I/O(iowait)、或是被虚拟化的 steal(被抢占),再决定对症下药。
# 1) 快速看系统负载与总体 CPU 使用
$ top -b -n1 | head -n5
top - 11:30:00 up 12 days, 2:01, 1 user, load average: 12.34, 11.98, 10.12
%Cpu(s): 92.0 us, 3.0 sy, 0.0 ni, 2.0 id, 3.0 wa
# 2) 更细:每个 CPU 的使用(查看是否存在核不均衡)
$ mpstat -P ALL 1 1
Linux 5.4.0 (host) 08/10/2025 _x86_64_ (8 CPU)
08:30:01 AM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle
08:30:01 AM all 92.0 0.00 3.0 3.0 0.0 0.0 0.0 0.0 2.0
08:30:01 AM 0 99.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0
08:30:01 AM 1 85.0 0.0 6.0 0.0 0.0 0.0 0.0 0.0 9.0
...
# 3) 找出占用最严重的进程
$ ps aux --sort=-%cpu | head -n 8
root 23456 95.0 1.2 123456 78900 ? R 11:29 120:00 /usr/bin/myapp --worker
判别:
%usr
高,且某个进程占比高 → 进程计算密集(业务逻辑/算法);%sys
高 → 内核开销高(例如频繁上下文切换、网络/磁盘中断);%iowait
高 → 可能是 IO 瓶颈(继续看 IO 部分);%steal
高 → 虚拟化宿主被抢占(云主机需联系云厂商或扩容)。# k8s 临时扩副本
$ kubectl scale deployment myapp --replicas=10 -n prod
deployment.apps/myapp scaled
renice
或把关键进程绑定到空闲核 taskset
:# 优先级调低(nice 值增大)
$ sudo renice +10 -p 23456
# 把进程绑定到 CPU 2 和 3
$ sudo taskset -cp 2,3 23456
示例输出(模拟):
$ sudo renice +10 -p 23456
23456 (process id) old priority 0, new priority 10
perf record
/ perf report
/ FlameGraph),找到热点后优化算法或改为异步处理;perf 快速示例(采样 10s):
# 需要 root,示例模拟命令
$ sudo perf record -F 99 -p 23456 -g -- sleep 10
$ sudo perf report --stdio | head -n 20
# 输出会显示最耗时的函数栈,便于定位
内存问题分两类:一是内存不足导致频繁 swap(影响响应),二是内存泄露使某服务占用持续增长。判断依据:free
、vmstat
、slabtop
、ps
。
# 1) 总览内存状态
$ free -m
total used free shared buff/cache available
Mem: 32768 25000 1024 123 5744 7000
Swap: 8192 512 7680
# 2) 观察短期页活动
$ vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
4 0 524288 102400 52480 300000 10 0 1024 128 3000 1000 60 30 5 5 0
...
# 3) 哪个进程占内存
$ ps aux --sort=-rss | head -n 10
appuser 34567 0.1 45.0 1234567 1500000 ? Sl 11:00 300:12 /usr/bin/myapp
# 4) slab 缓存检查(内核对象)
$ sudo slabtop -o
Active / Total Objects: 123456 / 234567
OBJS ACTIVE USE OBJ SIZE SLABS SIZE CACHE NAME
10240 5120 50% 64 80K 8192 kmalloc-64
...
判别:
available
很低且 swpd
不为 0 → 发生交换(swap);# 释放 pagecache
$ sudo sync; echo 1 | sudo tee /proc/sys/vm/drop_caches
1
小心:这会清空文件系统缓存,会影响 IO 性能,建议在低峰或先预警。
$ sudo sysctl vm.swappiness=10
vm.swappiness = 10
oom_score_adj
,防止关键进程被 OOM 杀死:# 给 critical pid 设置 oom_score_adj 为 -1000
$ echo -1000 | sudo tee /proc/34567/oom_score_adj
示例输出(模拟):
$ sudo sysctl vm.swappiness=10
vm.swappiness = 10
gdb
/valgrind
/heaptrack
做内存跟踪;jmap
/ jstack
/ heap dump 分析;net/http/pprof
)做 heap profile。Go pprof 示例如下(采样与生成报告):
# 在服务机器上采集 30s heap
$ curl http://127.0.0.1:6060/debug/pprof/heap > heap.out
# 使用 go tool pprof 进行分析
$ go tool pprof -svg ./myapp heap.out > heap.svg
磁盘瓶颈通常表现为高 await
、高 %util
(iostat),或大量等待导致 CPU 的 iowait
上升。需要区分是单块盘饱和、文件系统元数据锁竞争,还是网络存储(NFS、iSCSI)问题。
# 1) 磁盘总体 IO 性能(查看 %util、await)
$ iostat -x 1 3
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 0.00 0.00 0 100 0 102400 2048 12.34 45.67 0.00 45.67 2.00 95.00
# %util 近 100% 且 await 高 -> 磁盘成为瓶颈
# 2) 实时查看哪个进程在做最多 IO
$ sudo iotop -oPa --iter=3
Total DISK READ : 0.00 B/s | Total DISK WRITE : 512.00 K/s
PID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND
1234 be/4 appuser 0.00 B/s 512.00 K/s 0.00 % 0.00 % /usr/bin/myapp
# 3) 文件系统使用情况
$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 50G 45G 3.0G 94% /
# 4) 块队列长度(avgqu-sz)结合 %util 判断是否饱和
$ cat /sys/block/sda/stat
# 11个字段,通常看 avg queue depth 需用 iostat 更直观
判别:
%util
高(> 80%)且 avgqu-sz
大 → 磁盘饱和;await
高而 svctm
低 → 可能是队列过长或设备等待服务;rsync
热迁移:# 假设 /data 是热点目录,要迁移到 /mnt/fastdisk
$ rsync -aHAXv /data/ /mnt/fastdisk/data/
$ mount --bind /mnt/fastdisk/data /data
# 查看当前调度器
$ cat /sys/block/sda/queue/scheduler
noop [deadline] cfq
# 切换为 deadline
$ echo deadline | sudo tee /sys/block/sda/queue/scheduler
deadline
模拟输出:
$ echo deadline | sudo tee /sys/block/sda/queue/scheduler
deadline
noatime
、合理调整 journaling(ext4 的 commit 值);fstrim -v /
。网络问题会表现为延迟、丢包或吞吐率受限。检查顺序:链路(链路丢包/延迟)→ 本机网络栈(SOCKET 队列、tc 策略)→ 应用层(连接泄露)。
# 基本连通/延迟
$ ping -c 4 10.0.0.10
PING 10.0.0.10 (10.0.0.10): 56 data bytes
64 bytes from 10.0.0.10: icmp_seq=1 ttl=64 time=1.23 ms
...
# TCP 层面连接问题
$ ss -s
Total: 123 (kernel 456)
TCP: 789 (estab 100, closed 200, orphaned 0, timewait 50)
# 查看端口连接详情
$ ss -tn state established '( dport = :3306 or sport = :3306 )'
缓解:
tc
/iptables 做限速或连接数限制;sysctl -w net.core.rmem_max=...
;容器环境下,很多性能问题来源于资源配额不当或 cgroup 限制:
$ kubectl describe pod mypod -n prod
kubectl logs --previous
;%steal
高,请联系云厂商或考虑换实例规格。在现场我常用的一套顺序(在 1–3 分钟内跑完):
# 系统总体
top -b -n1 | head -n20
free -m
vmstat 1 5
iostat -x 1 3
df -h
# 进程级别
ps aux --sort=-%cpu | head
ps aux --sort=-%mem | head
# 网络
ss -s
ss -tn state established
# 容器 / k8s
kubectl get pods -A
kubectl top nodes
把这些输出截图/保存到事件工单中,便于后续复盘与分析。
1)对 CPU 峰值,临时扩容(Kubernetes):
kubectl scale deployment myapp --replicas=10 -n prod
2)对内存泄露,优雅下线并重启单实例:
kubectl drain node/node-1 --ignore-daemonsets --delete-local-data
systemctl restart myapp.service
3)对磁盘写满,归档并释放日志:
sudo mv /var/log/app.log /var/log/app.log.$(date +%F-%H%M)
sudo gzip /var/log/app.log.$(date +%F-%H%M)
sudo systemctl restart rsyslog
这些操作都有风险,执行前请确认变更窗口与回滚路径。
drop_caches
会把缓存击穿,短期内看似缓解,长期反而伤性能。每次事件结束后,请在工单里补全:
性能调优不是一次性的魔法,而是一种持续的工程:不断观察、不断剖析、不断改进。现场救火要快要稳,事后修复要彻底。你会发现,很多问题经过一次完整的定位与修复后,就再也不会重复抓你;这正是把“偶发事故”变成“可控变更”的意义。
这里我先声明一下,日常生活中大家都叫我波哥,跟辈分没关系,主要是岁数大了.就一个代称而已. 我的00后小同事我喊都是带哥的.张哥,李哥的. 但是这个称呼呀,在线下参加一些活动时.金主爸爸也这么叫就显的不太合适. 比如上次某集团策划总监,公司开大会来一句:“今个咱高兴!有请IT运维技术圈的波哥讲两句“ 这个氛围配这个称呼在互联网这行来讲就有点对不齐! 每次遇到这个情况我就想这么接话: “遇到各位是缘分,承蒙厚爱,啥也别说了,都在酒里了.我干了,你们随意!” 所以以后咱们改叫老杨,即市井又低调.还挺亲切,我觉得挺好.
运维X档案系列文章:
企业级 Kubernetes 集群安全加固全攻略( 附带一键检查脚本)
老杨的关于AI的号