写在文章开头
本文整理了Linux系统性能问题排查的通用方法论和实践,将针对以下三个经典场景展开探讨:
- I/O性能瓶颈
- CPU飙升
- 偶发CPU飙升
同时考虑到笔者文章的受众面大部分都是Java开发人员,所以复现问题故障的例子也都采用Java进行编码部署复现,对应的示例也都会在案例排查的最后展开说明。 我是 SharkChili ,Java 开发者,Java Guide 开源项目维护者。欢迎关注我的公众号:写代码的SharkChili,也欢迎您了解我的开源项目 mini-redis:github.com/shark-ctrl/...
为方便与读者交流,现已创建读者群。关注上方公众号获取我的联系方式,添加时备注加群即可加入。
常见系统巡检流程
查看系统基本运行信息
在正式介绍这些生产案例之前,我们先了解一些比较常见的系统巡检步骤,在日常监控巡检的时候,我们一般新查看系统的运行基本信息,所以我们优先会执行uptime查看系统整体运行情况和负载,以笔者的输出为例,可以看到uptime输出显示如下消息:
- 系统时间为23:08:23
- 当前系统运行1天4小时多
- 当前系统有两个用户登录
- 系统近1min、15min、30min的系统负载稳定在0
uptime指令可以反映一个时间段的系统运行负载,一般来说,若近1min的值远远低于15和30min的值,这可能就说明我们错过了系统反馈的故障:
bash
23:08:23 up 1 day, 4:02, 3 users, load average: 0.00, 0.00, 0.00
查看内核是否存在报错
然后我们就通过dmesg |tail查看内核环形缓冲区的消息,通过该指令可以看到一些系统消息,检查运行时报错,以笔者服务器的输出结果来看:
- 网络连接初始化失败
- hv_balloon动态内存信息
- Time jumped backwards, rotating即因为某个原因系统向后跳动了
- 系统缓存清理
less
[ 5.923407] WSL (206) ERROR: CheckConnection: getaddrinfo() failed: -5
[ 48.414734] hv_balloon: Max. dynamic memory size: 8126 MB
[ 48.590258] systemd-journald[53]: Time jumped backwards, rotating.
[ 605.106029] TCP: eth0: Driver has suspect GRO implementation, TCP performance may be compromised.
[ 676.028375] mini_init (190): drop_caches: 1
[ 1166.861172] mini_init (190): drop_caches: 1
[19373.591153] Adjusting hyperv_clocksource_tsc_page more than 11% (1467515026 vs 1862270976)
[48202.834581] mini_init (190): drop_caches: 1
[48988.179688] mini_init (190): drop_caches: 1
[81152.543659] mini_init (190): drop_caches: 1
查看虚拟内存使用情况
vmstat常用语查看虚拟内存、io、cpu运行耗时等指标,在进行巡检时我们一般使用vmstat 1进行每隔1s一次的输出,以笔者服务器为例:
针对进程的输出参数procs:
- r: 运行队列或者等待运行的进程,由于这个参数输出不反应io,所以可以很好判断系统的负载,如果r大于cpu的核心数就代表cpu已经饱和,而我们的数值为0,说明当前cpu空闲
- b:io阻塞队列为0
针对内存的参数组memory:
- swap已用空间为0
- free空间为6.75gb,内存空间还是充裕的
- si和so即swap空间换入和换出,目前使用率为0,不存在swap空间交换,系统io情况良好
针对磁盘io参数组:
- 每秒从磁盘读写的数据为14KiB、20KiB
- bo代表每秒系统响应硬件中断20次,in代表上下文切换最多520次,整体情况良好
cpu参数组:
- 通过us和sy可以反应用户态和内核态对于cpu的使用,以本例来看整体运行状况良好
- cpu idle为100基本处于空闲状态
- wa反应任务等待io,而我们这里输出的是0,所以整体情况也是空闲良好
css
procs -----------memory---------- ---swap-- -----io---- -system-- -------cpu-------
r b swpd free buff cache si so bi bo in cs us sy id wa st gu
0 0 0 7080860 24908 270132 0 0 14 20 520 0 0 0 100 0 0 0
0 0 0 7080840 24908 270172 0 0 0 0 538 457 0 0 100 0 0 0
cpu亲和力巡检
执行mpstat -P ALL 1,以笔者的输出结果来看,cpu整体使用率基本一致(使用率不高),并没有存在某个cpu使用率飙升的情况,若某个cpu使用率飙升则说明存在一个单线程在疯狂占用cpu时间片导致cpu过热:
perl
09:33:20 CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
09:33:21 all 0.67 0.00 1.34 0.00 0.00 0.17 0.00 0.00 0.00 97.83
09:33:21 0 1.00 0.00 1.00 0.00 0.00 0.00 0.00 0.00 0.00 98.00
09:33:21 1 0.00 0.00 1.01 0.00 0.00 1.01 0.00 0.00 0.00 97.98
09:33:21 2 1.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 99.00
09:33:21 3 0.00 0.00 1.01 0.00 0.00 0.00 0.00 0.00 0.00 98.99
09:33:21 4 0.00 0.00 2.00 0.00 0.00 0.00 0.00 0.00 0.00 98.00
09:33:21 5 1.98 0.00 2.97 0.00 0.00 0.00 0.00 0.00 0.00 95.05
09:33:21 CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
09:33:22 all 0.17 0.00 0.00 0.00 0.00 0.17 0.00 0.00 0.00 99.67
09:33:22 0 0.00 0.00 0.00 0.00 0.00 1.00 0.00 0.00 0.00 99.00
09:33:22 1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
09:33:22 2 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
09:33:22 3 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
09:33:22 4 0.99 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 99.01
09:33:22 5 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
09:33:22 CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
09:33:23 all 0.17 0.00 0.17 0.00 0.00 0.00 0.00 0.00 0.00 99.67
09:33:23 0 1.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 99.00
09:33:23 1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
09:33:23 2 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
09:33:23 3 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
09:33:23 4 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
09:33:23 5 0.00 0.00 0.99 0.00 0.00 0.00 0.00 0.00 0.00 99.01
^C
Average: CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
Average: all 0.33 0.00 0.50 0.00 0.00 0.11 0.00 0.00 0.00 99.05
Average: 0 0.67 0.00 0.33 0.00 0.00 0.33 0.00 0.00 0.00 98.67
Average: 1 0.00 0.00 0.34 0.00 0.00 0.34 0.00 0.00 0.00 99.33
Average: 2 0.33 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 99.67
Average: 3 0.00 0.00 0.34 0.00 0.00 0.00 0.00 0.00 0.00 99.66
Average: 4 0.33 0.00 0.66 0.00 0.00 0.00 0.00 0.00 0.00 99.00
Average: 5 0.66 0.00 1.32 0.00 0.00 0.00 0.00 0.00 0.00 98.01
检测进程摘要
键入pidstat 1可以滚动输出当前系统运行进程的摘要,相比于top的清屏输出,该指令可以更好的观察一段时间的系统负载:
perl
Linux 6.6.87.2-microsoft-standard-WSL2 (DESKTOP-0F6E7K1) 09/15/25 _x86_64_ (6 CPU)
09:35:48 UID PID %usr %system %guest %wait %CPU CPU Command
09:35:49 105 267 0.00 1.00 0.00 0.00 1.00 0 mysqld
09:35:49 UID PID %usr %system %guest %wait %CPU CPU Command
09:35:50 105 267 1.00 0.00 0.00 0.00 1.00 0 mysqld
09:35:50 UID PID %usr %system %guest %wait %CPU CPU Command
09:35:51 0 171 1.00 0.00 0.00 0.00 1.00 4 frpc
09:35:51 UID PID %usr %system %guest %wait %CPU CPU Command
09:35:52 105 267 1.00 0.00 0.00 0.00 1.00 0 mysqld
^C
Average: UID PID %usr %system %guest %wait %CPU CPU Command
Average: 0 171 0.25 0.00 0.00 0.00 0.25 - frpc
Average: 105 267 0.50 0.25 0.00 0.00 0.75 - mysqld
查看内存使用情况
这点相信大家都比较熟悉,一般情况下我们都是键入free -m查看系统空闲的运行内存,对应当前服务器内存空间基本空闲,而swap空间都被使用了:
yaml
total used free shared buff/cache available
Mem: 7876 828 6915 3 289 7048
Swap: 2048 0 2048
除了使用free命令查看整体内存使用情况外,当怀疑存在内存泄漏时,我们还可以使用以下工具进行更详细的分析:
-
pmap命令:查看进程的内存映射情况
ini# 查看指定进程的内存映射 pmap -x [PID]
-
smem命令:提供更详细的内存使用报告,包括USS、PSS、RSS等指标
bash# 安装smem sudo apt install smem # 查看内存使用情况 smem -s rss -r | head
-
/proc/meminfo:查看系统详细的内存信息
bashcat /proc/meminfo
当发现内存使用持续增长且不释放时,可能存在内存泄漏问题,需要结合应用层的诊断工具(如Java应用的jmap、jstat等)进一步分析。
查看io使用情况
关于磁盘io笔者推荐使用iostat -xz 1,即可查看磁盘基本读写情况,我们可以通过:
- r/s、w/s、rkB/s、wkB/s 查看当前系统的读写流量
- await查看当前系统平均io等待时间
- avgqu-sz查看向设备发出的平均请求数,如果大于1则说明则说明设备已经饱和
- util反应设备使用率,若大于60%基本可以io已趋近于饱和
从笔者的服务器输出结果来看几个await的百分比基本为例,util即磁盘利用率也没有飙升,系统io情况良好:
bash
Linux 6.6.87.2-microsoft-standard-WSL2 (DESKTOP-0F6E7K1) 09/14/25 _x86_64_ (6 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
0.09 0.00 0.19 0.00 0.00 99.72
Device r/s rkB/s rrqm/s %rrqm r_await rareq-sz w/s wkB/s wrqm/s %wrqm w_await wareq-sz d/s dkB/s drqm/s %drqm d_await dareq-sz f/s f_await aqu-sz %util
sda 0.01 0.72 0.00 27.46 0.40 65.57 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
sdb 0.00 0.04 0.00 36.65 0.50 35.94 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
sdc 0.00 0.02 0.00 0.00 0.08 22.73 0.00 0.00 0.00 0.00 1.50 2.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 2.00 0.00 0.00
sdd 0.23 13.47 0.17 42.55 0.36 59.20 2.73 20.75 1.07 28.22 0.61 7.60 0.20 122.27 0.00 1.74 0.19 611.44 0.18 0.66 0.00 0.29
查看网卡使用情况
最后一个就是查看网络io情况了,笔者一般推荐使用sar -n DEV 1,即可查看各个接口的读写速率情况了:
bash
23:38:11 IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s %ifutil
23:38:12 lo 7.00 7.00 0.68 0.68 0.00 0.00 0.00 0.00
23:38:12 eth0 9.00 7.00 0.81 0.72 0.00 0.00 0.00 0.00
23:38:12 IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s %ifutil
23:38:13 lo 18.81 18.81 5.98 5.98 0.00 0.00 0.00 0.00
23:38:13 eth0 12.87 13.86 1.31 5.92 0.00 0.00 0.00 0.00
23:38:13 IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s %ifutil
23:38:14 lo 17.00 17.00 1.60 1.60 0.00 0.00 0.00 0.00
23:38:14 eth0 11.00 8.00 0.97 1.33 0.00 0.00 0.00 0.00
上述指标反映了网络io的整体情况,实际上我们可能还需要结合带宽进行判断,所以我们需要执行如下指令完成ethtool工具的安装:
sudo apt install ethtool
然后我们就可以通过ethtat eth0查看网卡的带宽连接速度为10000Mb/s,此时我们就可以结合带宽情况和上述io推算出网络资源使用情况:
yaml
Settings for eth0:
Supported ports: [ ]
Supported link modes: Not reported
Supported pause frame use: No
Supports auto-negotiation: No
Supported FEC modes: Not reported
Advertised link modes: Not reported
Advertised pause frame use: No
Advertised auto-negotiation: No
Advertised FEC modes: Not reported
Speed: 10000Mb/s
Duplex: Full
Auto-negotiation: off
Port: Other
PHYAD: 0
Transceiver: internal
netlink error: Operation not permitted
Current message level: 0x000000f7 (247)
drv probe link ifdown ifup rx_err tx_err
Link detected: yes
除了基本的网络流量监控,我们还可以通过以下方式进一步诊断网络问题:
-
netstat/ss命令:查看网络连接状态,识别是否存在大量TIME_WAIT或CLOSE_WAIT连接
css# 查看TCP连接状态统计 netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
-
tcpdump抓包分析:用于深入分析网络包的详细内容,识别丢包、重传等问题
bash# 抓取eth0网卡上的TCP包 tcpdump -i eth0 tcp
-
ping和traceroute:诊断网络延迟和路由路径问题
本文使用 markdown.com.cn 排版