从入门到精通:Linux系统性能问题定位与解决方案大全

写在文章开头

本文整理了Linux系统性能问题排查的通用方法论和实践,将针对以下三个经典场景展开探讨:

  1. I/O性能瓶颈
  2. CPU飙升
  3. 偶发CPU飙升

同时考虑到笔者文章的受众面大部分都是Java开发人员,所以复现问题故障的例子也都采用Java进行编码部署复现,对应的示例也都会在案例排查的最后展开说明。 我是 SharkChili ,Java 开发者,Java Guide 开源项目维护者。欢迎关注我的公众号:写代码的SharkChili,也欢迎您了解我的开源项目 mini-redis:github.com/shark-ctrl/...

为方便与读者交流,现已创建读者群。关注上方公众号获取我的联系方式,添加时备注加群即可加入。

常见系统巡检流程

查看系统基本运行信息

在正式介绍这些生产案例之前,我们先了解一些比较常见的系统巡检步骤,在日常监控巡检的时候,我们一般新查看系统的运行基本信息,所以我们优先会执行uptime查看系统整体运行情况和负载,以笔者的输出为例,可以看到uptime输出显示如下消息:

  1. 系统时间为23:08:23
  2. 当前系统运行1天4小时多
  3. 当前系统有两个用户登录
  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查看内核环形缓冲区的消息,通过该指令可以看到一些系统消息,检查运行时报错,以笔者服务器的输出结果来看:

  1. 网络连接初始化失败
  2. hv_balloon动态内存信息
  3. Time jumped backwards, rotating即因为某个原因系统向后跳动了
  4. 系统缓存清理
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:

  1. r: 运行队列或者等待运行的进程,由于这个参数输出不反应io,所以可以很好判断系统的负载,如果r大于cpu的核心数就代表cpu已经饱和,而我们的数值为0,说明当前cpu空闲
  2. b:io阻塞队列为0

针对内存的参数组memory:

  1. swap已用空间为0
  2. free空间为6.75gb,内存空间还是充裕的
  3. si和so即swap空间换入和换出,目前使用率为0,不存在swap空间交换,系统io情况良好

针对磁盘io参数组:

  1. 每秒从磁盘读写的数据为14KiB、20KiB
  2. bo代表每秒系统响应硬件中断20次,in代表上下文切换最多520次,整体情况良好

cpu参数组:

  1. 通过us和sy可以反应用户态和内核态对于cpu的使用,以本例来看整体运行状况良好
  2. cpu idle为100基本处于空闲状态
  3. 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命令查看整体内存使用情况外,当怀疑存在内存泄漏时,我们还可以使用以下工具进行更详细的分析:

  1. pmap命令:查看进程的内存映射情况

    ini 复制代码
    # 查看指定进程的内存映射
    pmap -x [PID]
  2. smem命令:提供更详细的内存使用报告,包括USS、PSS、RSS等指标

    bash 复制代码
    # 安装smem
    sudo apt install smem
    
    # 查看内存使用情况
    smem -s rss -r | head
  3. /proc/meminfo:查看系统详细的内存信息

    bash 复制代码
    cat /proc/meminfo

当发现内存使用持续增长且不释放时,可能存在内存泄漏问题,需要结合应用层的诊断工具(如Java应用的jmap、jstat等)进一步分析。

查看io使用情况

关于磁盘io笔者推荐使用iostat -xz 1,即可查看磁盘基本读写情况,我们可以通过:

  1. r/s、w/s、rkB/s、wkB/s 查看当前系统的读写流量
  2. await查看当前系统平均io等待时间
  3. avgqu-sz查看向设备发出的平均请求数,如果大于1则说明则说明设备已经饱和
  4. 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

除了基本的网络流量监控,我们还可以通过以下方式进一步诊断网络问题:

  1. netstat/ss命令:查看网络连接状态,识别是否存在大量TIME_WAIT或CLOSE_WAIT连接

    css 复制代码
    # 查看TCP连接状态统计
    netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
  2. tcpdump抓包分析:用于深入分析网络包的详细内容,识别丢包、重传等问题

    bash 复制代码
    # 抓取eth0网卡上的TCP包
    tcpdump -i eth0 tcp
  3. ping和traceroute:诊断网络延迟和路由路径问题

本文使用 markdown.com.cn 排版

相关推荐
bobz9652 小时前
OVS-DOCA 符合 vDPA 设计
后端
bobz9652 小时前
OVS-DOCA 和 VPP-DPDK 对比
后端
阿杆2 小时前
同事嫌参数校验太丑,我直接掏出了更优雅的 SpEL Validator
java·spring boot·后端
无奈何杨2 小时前
CoolGuard增加枚举字段支持,条件编辑优化,展望指标取值不同
前端·后端
这里有鱼汤2 小时前
小白必看:QMT里的miniQMT入门教程
后端·python
brzhang3 小时前
当AI接管80%的执行,你“不可替代”的价值,藏在这20%里
前端·后端·架构
绝无仅有3 小时前
后端 Go 经典面试常见问题解析与总结
后端·面试·github
绝无仅有3 小时前
后端工程师面试常见问题与回答解析总结
后端·面试·github
程序员爱钓鱼5 小时前
Go语言实战案例 — 项目实战篇:简易博客系统(支持评论)
前端·后端·go