当前位置:首页>Linux>Linux系统性能排查全景指南与实战避坑

Linux系统性能排查全景指南与实战避坑

  • 2026-10-11 07:51:57
Linux系统性能排查全景指南与实战避坑

导语: 今天,我们来聊聊当服务器性能出现瓶颈时,如何建立一套标准、高效、无死角的排查方法论,这不仅是一篇干货,更是你深夜保命的 SRE 生存指南。


一、告别无头苍蝇式排查

很多运维兄弟排查问题时,上来就敲个 top,看着一堆跳动的数字发呆,真正的老鸟,会利用性能调优大师 Brendan Gregg 提出的USE(Utilization 使用率、Saturation 饱和度、Errors 错误)方法论,建立对系统的宏观认知。

别急着下潜,先在水面上看看全貌,请按顺序敲下这几个命令:

1. uptime:

uptime

 16:20:15 up 45 days, 12:00,  1 users,  load average: 45.15, 20.05, 10.12

重点看最后三个数字(1分钟、5分钟、15分钟的平均负载),如果 1 分钟的负载远高于 15 分钟,说明是突发流量;如果 15 分钟负载一直很高,说明系统长期处于高压状态。

避坑指南: Load Average 不等于 CPU 使用率,在 Linux 中,处于不可中断睡眠状态(比如等待磁盘 I/O)的进程也会被计入 Load,Load 极高但 CPU 空闲时,去查磁盘。

2. dmesg | tail:

内核在遇到致命问题时一定会发牢骚,这里是你发现底层故障的捷径。看到 Out of memory 说明内存爆了;看到 TCP: time wait bucket table overflow 说明网络连接数过多。

3. vmstat 1 3:

这个命令每秒输出一次系统的整体健康度,连续输出 3 次,包含进程、内存、I/O 和 CPU 的核心指标。

vmstat 1 3

procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 8  0      0 123456  45678 890123    0    0     0     0 1200  900 85 15  0  0  0

vmstat 1 3

procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  3      0 120000  45678 890123    0    0 50000     0 3000 4500  5 10 15 70  0
  • 看第一部分(CPU瓶颈):r(运行队列)高达 8,而你可能只有 4 核 CPU,同时 us(用户态)高达 85%,id(空闲)为 0。结论:典型的 CPU 瓶颈,业务代码把 CPU 打满了。
  • 看第二部分(I/O瓶颈):b(阻塞队列)变成了 3,同时 wa(I/O 等待)飙升到了 70%,bi(块设备读取)非常高。结论:典型的磁盘 I/O 瓶颈,进程都在排队等物理磁盘读写,CPU 其实很闲。

二、四大子系统微观剖析

1. CPU 飙高排查思路

假设你通过 vmstat 发现 us(用户态 CPU)高达 90%。

  • 找进程: 用 top 按 P 排序,或 pidstat -u 1,找到霸占 CPU 的 PID(假设为 10086)。
  • 找线程: 执行 top -H -p 10086,找到占用最高的特定线程 TID,用于去 Java 的 jstack 等日志里对应代码行。
  • 看调用栈: 如果代码不是你写的,直接用 perf top -p 10086 看它在干嘛。
perf top -p 10086

Overhead  Shared Object       Symbol
  45.20%  libjvm.so           [.] GCTaskThread::run()
  20.15%  [kernel]            [k] _raw_spin_unlock_irqrestore

深度解析: 如果你看到排名第一的是 GCTaskThread::run(),说明 Java 正在疯狂进行垃圾回收(Full GC),这就是典型的“内存泄漏导致频繁 GC,进而把 CPU 打满”的连环案,排查方向立刻转向 JVM 堆内存。

2. 内存泄漏与 OOM 现场取证

  • 辨别真假内存不足: 执行 free -h,新手看到 free 剩下几十 MB 就会慌,其实真正判断应用可用内存的是 available 列,如果 available 见底,那才是真的危急。
  • 找吃内存大户:top 按 M 排序,重点看 RES(常驻内存),而不是 VIRT(虚拟内存)。
  • OOM 死亡回放: 去 /var/log/messages 搜 Killed process。

3. 磁盘 I/O 瓶颈:看不见的慢动作

I/O 问题最恶心,会拖慢整个系统,表现出玄学卡顿,直接掏出神器 iostat -xz 1:

iostat -xz 1

Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
vda               0.00     5.00  150.00  200.00  4096.00  8192.00    70.15     5.50  125.00   80.00  150.00   2.85 100.00%
  • 致命的 100%: 看到最后面的 %util 达到 100.00% 了吗?这意味着这一秒钟内,磁盘彻底被榨干。
  • 夸张的 await:await 达到了 125.00(毫秒),现代 SSD 正常情况下应在 1-5ms 内,超过 100ms 说明 I/O 队列严重堆积,上游业务肯定已经超时。

此时再用 iotop -o 抓取疯狂写磁盘的内鬼进程,元凶一目了然。

4. 网络疑难杂症:从玄学到科学

  • 看连接状态:ss -s,发现几千个 TIME_WAIT 说明短连接耗尽了端口;大量 CLOSE_WAIT 绝对是业务代码里忘了关闭 Socket 连接。
  • 查网卡带宽:sar -n DEV 1,对比 rxkB/s 和 txkB/s 看是否跑满了物理带宽上限。
  • 抓包必杀: 当宏观指标正常但网络不通,直接上 tcpdump 导出 pcap 文件,扔进 Wireshark 分析三次握手和重传包,数据包不会撒谎。

三、K8S 排查特供

传统的 Linux 经验在 Kubernetes 和 Docker 面前,有时会失效,因为你加了一层 Cgroups 和 Namespace。

Node 负载很低,但 Pod 巨卡无比

你用 top 看宿主机,CPU 闲得发慌,但容器里的业务就是说延迟高。

真相:CPU 限流,当应用瞬间突发需要大量计算时,即使宿主机有大量空闲,Cgroups 也会无情地把你的进程暂停。

怎么查: 不要再看 top 了,直接去查宿主机上对应的 Cgroups 状态文件:

cat /sys/fs/cgroup/cpu/cpu.stat

nr_periods 54321
nr_throttled 12500
throttled_time 450000000000
  • nr_throttled: 进程被限流的周期数,如果这个值占总周期的比例很高(这里 12500 / 54321 约 20% 时间被挂起),说明限流极其严重。

破局之法: 在 K8S 中调大 resources.limits.cpu,或检查应用(如 Java GC 线程数、Go GOMAXPROCS)是否错误识别了宿主机的物理核数导致并发过高。


四、eBPF 显微镜

当你把上述所有工具都用了一遍,依然查不出偶发性的玄学卡顿,你需要祭出核武器:eBPF,通过 bcc-tools,在不修改代码、不重启服务的情况下,洞察内核最深处的动作。

1. execsnoop:

有些疯狂报错的脚本几毫秒就结束了,top 根本抓不到,execsnoop 通过监听 execve 系统调用,让所有新建进程无处遁形。

# 实时查看全系统所有新创建的进程,并显示参数
execsnoop -T

TIME(s)     PCOMM            PID    PPID   RET ARGS
03:25:01    cron             4521   1024     0 /usr/sbin/cron -f
03:25:01    sh               4522   4521     0 /bin/sh -c /app/monitor.sh
03:25:02    curl             4523   4522     0 /usr/bin/curl -s http://internal.api/health

解析: PID 与 PPID 父子关系一目了然,清晰展示了 cron 拉起了 monitor.sh 脚本,正在疯狂 curl。

2. opensnoop:

配置怎么改都不生效?应用启动报错但没写缺哪个文件?opensnoop 直接监控全系统文件打开行为。

# 实时监控文件打开情况,并显示错误信息
opensnoop -x

PID    COMM               FD ERR PATH
10086  java               12   0 /app/logs/error.log
20485  nginx              -1   2 /etc/nginx/conf.d/proxy.conf

解析: 注意 ERR 为 2,代表 ENOENT(文件不存在),这就秒杀了“Nginx 莫名报错”的问题,直接锁定了它试图加载不存在的 proxy.conf。

3. biolatency:

iostat 的“平均延迟”往往会掩盖长尾问题(99% 的 I/O 极快,1% 的 I/O 耗时数秒),biolatency 能够以直方图形式,展现真实分布。

# 追踪块设备 I/O 延迟分布(微秒级)
biolatency -m

  usecs               : count    distribution
    16 -> 31         : 128      |********** |
    32 -> 63         : 512      |****************************************|
    64 -> 127        : 231      |****************** |
...
   2097152 -> 4194303    : 0        |                                        |
   4194304 -> 8388607    : 3        |* |

解析: 绝大多数 I/O 集中在 32 -> 63 微秒,性能极好,但看最后一行,有 3 个请求耗时落在4秒到8秒之间,这就是导致接口随机超时的罪魁祸首,通常预示着底层存储硬件瓶颈或宿主机 I/O 争抢严重。


五、 写在最后:

性能排查,从来不是靠死记硬背几个命令参数就能搞定的,它考察的是工程师对计算机体系结构的深刻理解。

下一次,当报警再次响起,希望你能从容地按照 USE 模型层层递进,从系统负载到 Cgroups 限制,从常规指标到 eBPF 追踪,用数据说话,用逻辑破局。

毕竟,SRE 的价值,不在于重启服务器的速度有多快,而在于能在混沌的故障中,精准地找到那根牵一发而动全身的线头。

最新文章

随机文章