检测 Linux 性能

针对 Linux 大部分性能指标采集, 需要用到对应相关的工具集, 这里提供目前比较主流的 Linux 检测手段:

  • perf: CPU 性能检测采集
  • iperf3: 网络性能检测采集
  • iostat: 磁盘IO监控
  • sar: 全能监控数据采集

CPU 性能检测

perf 是 Linux 系统下的性能分析工具(Performance Counters for Linux), 用于针对
CPU|内存|磁盘I/O|网络|进程/线程等系统资源的使用情况进行全方位的采样和分析.

这里采用 Debian 发行版来说明, 其他发行版只需要找 perf|performance 相关包安装即可:

1
2
3
4
5
6
# 安装依赖, 这里有的教程说是 linux-perf 或者 perf, 可能有的版本变迁之后更改包名
sudo apt install performance-tools

# 查看目前监控工具版本
# 需要注意: 系统性能采集本身是很高级的功能, 所以大部分情况都是需要用到 root 高级权限
sudo perf --version # 这里目前版本为 perf version 6.14.11

这里之后就是准备采集到具体指标信息, 建议可以参照文档来进行调试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# 参考文档: https://www.man7.org/linux/man-pages/man1/perf.1.html

# 实时 CPU 性能火焰监控, 核心使用方法
# 用于分析占用 CPU 最高的函数 / 进程 / 模块
sudo perf top -g
# 有的时候会提示让你选择, 比如 cpu_atom 和 cpu_core, 这是因为 CPU 采用大小核结构
# cpu_core: P-Core, Performance Core | 性能核, 算力强、主频高、缓存大,单核心性能拉满, 支持超线程
# cpu_atom: E-Core, Efficient Core | 能效核, 功耗低、能效比高、核心数多, 单核心性能弱于 P 核, 但胜在数量多、占用资源少
# 服务器很多时候都是只有 P-Core, 因为本身是服务器不讲究功耗节能, 要求的是最大限度释放核心性能, 所以既有 cpu_core
# 部分内核版本中, cpu_atom 也可能显示为 cpu_efficiency, cpu_core 也可能显示为 cpu_performance, 含义完全一致只是命名不同

# 选择主要核心之后就可以看到对应的列表, 主要的三个指标
# Children/Self/Shared Object/Symbol
#
# - Children: 代表子树占比, 为当前函数 + 它调用的所有子函数合计消耗的 CPU 占比, 代表整个调用链路的总算力消耗
# 若 Children 很高, Self 很低 → 该函数本身不耗 CPU, 它调用的子函数才是真正瓶颈
# 如果出现 Children 很高, Self 很低的情况, 需要检查下是不是程序内部业务代码逻辑是不是编写正确
# 但是这个指标不是唯一的, 因为确实有些业务必须要占用大量资源来处理, 所以这方面只能参考
#
# - Self: 代表程序自身 CPU 占比, 为当前函数自身代码执行消耗的 CPU 占比, 不包含它调用的子函数, 代表函数本身的算力消耗
# 若 Self 占比越高 → 该函数自身是纯 CPU 密集型(如循环、计算、序列化),是直接性能瓶颈, 优先优化这个函数本身
#
# - Shared Object: 代表所属模块|程序, 用于确定当前热点函数属于哪个程序/内核模块
# 明确 CPU 高耗是业务进程、还是内核、还是第三方库, 常见取值如下
# [kernel] - 内核调用, 系统级瓶颈(如上下文切换频繁、内核锁竞争)
# nginx/clickhouse-server - 业务进程, 进程任务占用瓶颈
# libc.so/libpthread.so - 系统库, 业务代码调用系统库的逻辑低效(如频繁内存分配、线程锁)
#
# - Symbol: 代表 CPU 占比最高的具体函数名称, 是性能分析的终点, 能够精确检索到代码层面
# 确定瓶颈是 用户态函数/内核态函数/匿名符号 哪个方面导致的问题
# 用户态函数 - 如 kafka_consumer_poll()、data_process() → 业务代码写的函数, 可直接优化
# 内核态函数 - 函数名前带 [kernel], 如 schedule()、sys_read() → 内核逻辑, 需调系统参数/内核配置解决
# 匿名符号 - 显示为 0xffffffffxxxxxx → 程序无调试符号, 需给程序加 -g 编译/安装调试包
#
# 核心的指标就是 Self + Children, 如果占用异常高的时候就要分析内部调用确定是代码问题还是系统问题, 而简单来看
# Self → 函数「自己」耗CPU → 优化函数本身
# Children → 函数「全家」耗CPU → 优化它调用的子函数


# 进去火焰图之后的操作如下
# ↑ ↓ 方向键 → 上下滚动列表,查看更多热点函数
# Enter → 选中某行函数,展开/收起 -g 的调用栈
# q → 退出 perf top 监控界面
# s → 切换排序方式(按 Self/Children 排序,优先按 Self 排)
# /xxx → 搜索关键字(如 /java 只看Java进程的热点、/kafka 只看kafka相关函数)
# d → 按进程PID过滤(输入目标PID,只显示该进程的CPU热点,精准无噪音)
# P → 按CPU核心过滤(只看指定核心的负载,适合大小核服务器)


# 开始记录 CPU 的性能分析报告
# perf record -e task-clock,cache-misses,cycles {程序二进制}

# 记录目前服务器 60 秒内的所有性能报告, 其中以每秒99次频率进行采样检测
sudo perf record -F 99 -a -g -- sleep 60 # 执行之后要等 60s 等待报告生成

# 耗费 60 秒收集之后就可以导出对应报告
# 模板默认版本不支持 JSON 输出, 只能生成默认 text 报告, 为了兼容性最好导出 txt 之后做每行数据分析
sudo perf report -i perf.data -g --stdio > perf_report.txt

# 纯文本结构化报告, 会打印父子节点分叉
sudo perf report -i perf.data -g --stdio --sort overhead > perf_struct.txt

# 导出perf原始结构化数据
sudo perf script -i perf.data > perf_raw.data

另外我很不喜欢大小核 CPU 的问题就是因为可能出现莫名其妙的调度问题, 比如最希望释放能效的程序会被分配到节能的能效核.

其中以英特尔的 CPU 调度问题最严重, 不过仅仅也只有家用服务器会影响到, 最多是 NAS 用户会出现这种问题, 可以通过内核参数禁用能效核心.

网络性能检测

iperf3 目前是比较常用的网络速度检测工具, 用于负责多种网络状态测试:

1
2
3
4
5
# 安装依赖
sudo apt install -y iperf3

# 查看目前版本
sudo iperf3 --version # iperf 3.16 (cJSON 1.7.15)

一般 iperf3 多用于内网测速效率判断, 确认内网的网络是否能够跑满网络带宽, 外网检测比较复杂所以不能单纯用 iperf3 分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# 注意: 如果要测速必须要保证内网有最少两台实体服务器/NAS, 才能正确获取到性能指标

# 1. 首先必须要在准备测试的设备创建服务端
sudo iperf3 -s # 默认监听端口为 5201, 可以通过 -p <端口> 指定监听服务端口
# 不要在同一个服务上启动服务端同时启动客户端进行测试, 这种测速方式是没用的


# 2. 其他服务器发起正向测试, 用于检测 客户端 → 服务器 的网络速率, 可以看作是上传速率
# iperf3 -c <服务器IP>
sudo iperf3 -c 192.168.1.9
# 最后可能输出速度如下
# [ ID] Interval Transfer Bitrate Retr
# [ 5] 0.00-10.00 sec 99.9 GBytes 85.8 Gbits/sec 0 sender
# [ 5] 0.00-10.00 sec 99.9 GBytes 85.8 Gbits/sec receiver

# 3. 其他服务器发起反向测试, 用于检测 服务器 → 客户端 的网络速率, 可以看作是下载速率
sudo iperf3 -c 192.168.1.9 -R

# 4. 其他服务器发起双向测试, 同时测试上传和下载速率
sudo iperf3 -c 192.168.1.9 --bidir
# 最后的速率结果可能如下:
# [ ID][Role] Interval Transfer Bitrate Retr
# [ 5][TX-C] 0.00-10.00 sec 86.8 GBytes 74.5 Gbits/sec 0 sender
# [ 5][TX-C] 0.00-10.00 sec 86.8 GBytes 74.5 Gbits/sec receiver
# [ 7][RX-C] 0.00-10.00 sec 87.7 GBytes 75.3 Gbits/sec 36 sender
# [ 7][RX-C] 0.00-10.00 sec 87.7 GBytes 75.3 Gbits/sec receiver

# 如果需要输出成 JSON 报告, 可以追加参数 --json --logfile <文件名>
# 可以提供给监控文件采集对应的数据, 用于做服务器的状态监控
sudo iperf3 -c 192.168.1.9 --bidir --json --logfile iperf3.json


# 5. 另外还有 UDP 的吞吐测速判断, 适合测试视频流、实时数据传输等 UDP 业务场景
# -u 指定 UDP 协议, -t 指定测试时长(秒), -b 指定带宽上限
sudo iperf3 -c 192.168.1.9 -u -b 1G -t 10


# 6. 实际内网环境都是多线程并发很激烈, 所以需要模拟下这部分并发
# -P <线程数> 代表模拟业务并发线程
# 这里模拟内网 10G 带宽, 开 4 线程区来测速
sudo iperf3 -c 192.168.1.9 -b 10G -P 4 -R
# [ ID] Interval Transfer Bitrate Retr
# [ 5] 0.00-10.00 sec 11.6 GBytes 10.0 Gbits/sec 0 sender
# [ 5] 0.00-10.00 sec 11.6 GBytes 10.0 Gbits/sec receiver
# [ 7] 0.00-10.00 sec 11.6 GBytes 10.0 Gbits/sec 0 sender
# [ 7] 0.00-10.00 sec 11.6 GBytes 10.0 Gbits/sec receiver
# [ 9] 0.00-10.00 sec 11.6 GBytes 10.0 Gbits/sec 0 sender
# [ 9] 0.00-10.00 sec 11.6 GBytes 10.0 Gbits/sec receiver
# [ 11] 0.00-10.00 sec 11.6 GBytes 10.0 Gbits/sec 0 sender
# [ 11] 0.00-10.00 sec 11.6 GBytes 10.0 Gbits/sec receiver
# [SUM] 0.00-10.00 sec 46.6 GBytes 40.0 Gbits/sec 0 sender
# [SUM] 0.00-10.00 sec 46.6 GBytes 40.0 Gbits/sec receiver

这里的网络速率有比较简单指标判断, 需要学习看这部分的指标:

  • Interval → 测速时间区间, 时间越长, 测速结果越精准, 可通过 -t 参数调整

  • Transfer → 测速周期内总传输数据量, 仅作为参考, 结合Bitrate看更有意义

  • Bitrate → 实际网络传输速率(核心指标), 若该值 ≈ 内网物理带宽 则代表网络正常且带宽跑满

    • 百兆网卡 ≈ 94.1 Mbits/sec ≈ 94.1 Mbits/sec÷8 ≈ 11.8 MB/s
    • 千兆网卡 ≈ 940 Mbits/sec ≈ 940 Mbits/sec÷8 ≈ 117.5 MB/s
    • 万兆网卡 ≈ 9.4 Gbits/sec ≈ 9.4 Gbits/sec÷8 ≈ 1.175 GB/s
    • 25G 网卡 ≈ 23.8 Gbits/sec ≈ 23.8 Gbits/sec÷8 ≈ 2.975 GB/s
  • Retr → 数据包重传次数(核心指标), 测速周期内因网络丢包导致的数据包重传数量, 也就是数据包重传次数, 数值越大链路质量越差

单位区分: Mbits/sec 是网卡链路带宽单位, MB/s 是文件传输的实际速度单位, 两者换算必须除以 8

注意: 这部分速率换算公式为 1 GB/s = 8 Gbits/sec, 也就是 测速显示 8 Gbits/sec, 实际文件传输速度约 1 GB/s.

内网应该尽可能保证达到 千兆网卡(117.5 MB/s) 的速度, 方便做内部的数据传输场景

有的小型服务器如果宣称支持千兆网络, 但是速率没有到达最低 100MB/s|940Mbits/sec 就需要判断网络环境哪里被干扰.

内网实际传输受网线、交换机、CPU 负载影响, 速率会略有下降, 但是降低的值不会偏差太大, 10% 以内偏差都是正常

如果需要构建家庭内网, 这些指标都是十分重要的判断方式, 用来判断是否最大程度跑满家庭的网络带宽.

一般来说网络速率跑满可以按照以下流程处理:

  • 网线问题: 更换超五类 / 六类网线, 避免使用劣质线材(千兆网络对网线要求高)

  • 交换机限制: 检查交换机端口是否被手动限速为 100 Mbps, 确保交换机端口为千兆口

  • CPU 负载过高: 测速时用 top 查看 CPU 使用率, 若 ≥ 80% → CPU 瓶颈导致无法跑满带宽, 需关闭其他高耗进程

  • 网卡驱动问题: 更新网卡驱动(需要及时更新网卡驱动)

至于 WIFI 速率跑满千兆网络, 应该说目前还不是这么乐观, 虽然 WiFi 6(802.11ax)WiFi 5(802.11ac Wave 2) 理论上能够达到,
但也是基于无干扰的实验室环境下, 一旦距离过长或者阻隔物体过多, 那么很大概率是只能回退成百兆带宽的情况.

硬盘性能检测

最后就是硬盘性能检测, Linux 这部分套件就比较多, 分析起来也相对容易:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 这部分原生工具 dddf 就可以测试
# 生成 /tmp/disk_write_test 测试写入 1G 的本地测试数据
# 检测写入速度, oflag 规避缓存处理
dd if=/dev/zero of=/tmp/disk_write_test bs=1G count=1 oflag=direct
# 这里输出如下信息:
# 输入了 1+0 块记录
# 输出了 1+0 块记录
# 1073741824 字节 (1.1 GB, 1.0 GiB) 已复制,0.599968 s,1.8 GB/s

# 测试硬盘读取速度
dd if=/tmp/disk_write_test of=/dev/null bs=1G count=1 iflag=direct
# 这里输出如下信息:
# 输入了 1+0 块记录
# 输出了 1+0 块记录
# 1073741824 字节 (1.1 GB, 1.0 GiB) 已复制,0.363162 s,3.0 GB/s

# 最后删除生成文件
rm -f /tmp/disk_write_test

# df 查看硬盘容量使用率+挂载信息, 排查磁盘满导致的性能问题
# -h 人性化单位显示, -T 显示硬盘文件系统格式(ext4/xfs等)
df -hT


# 这里我是外部扩展出来的机械硬盘, 用于查看机械和固态硬盘的差距
# /data 是外部扩展硬盘, 这里测试写入速度
dd if=/dev/zero of=/data/disk_write_test bs=1G count=1 oflag=direct
# 输入了 1+0 块记录
# 输出了 1+0 块记录
# 1073741824 字节 (1.1 GB, 1.0 GiB) 已复制,5.69057 s,189 MB/s

# 测试读取速率
dd if=/data/disk_write_test of=/dev/null bs=1G count=1 iflag=direct
# 输入了 1+0 块记录
# 输出了 1+0 块记录
# 1073741824 字节 (1.1 GB, 1.0 GiB) 已复制,6.34121 s,169 MB/s

# 最后删除生成文件
rm -f /data/disk_write_test

注意: 对于外部扩展的硬盘, 不要在系统盘根目录测速; 优先在业务数据盘测试, 一般是在扩展的硬盘生成测试文件.

而如果想要让本地文件速率贴合千兆带宽, 必须确保硬盘的速度大等于千兆网络速度, 否则硬盘速度将会成为瓶颈

对于硬盘来说, 以下指标都是相对比较正常的:

  • 机械硬盘(HDD): 顺序读写 ≈ 80-150 MB/s 即为正常

  • 固态硬盘(SSD): 顺序读写 ≈ 300-500 MB/s(SATA)即为达标

  • NVMe 固态(NVMe): 顺序读写 ≈ 1000-3500 MB/s, 是目前最快的硬盘类型, 速率轻松破千兆

另外还有多线程因素, 这部分读写也是会影响到最终的传输速率

一般来说如果要构建内网千兆网络的话, 那么硬盘读写速度最低也不能低于 117.5 MB/s, 否则会触发网络传输的瓶颈.