Linux 性能基准测试全解析:FIO / sysbench / mbw / iperf3 跑出真实数字
系列导读:《Linux 从入门到高阶:4 节点华为云 ECS 全实操》第 5 篇。
所有实验均在真实云主机执行,输出可复现(机器代号 node1~node4,公网 IP 已脱敏为 120.46.x.x / 121.36.x.x,内网保留 192.168.0.x)。
本篇基准测试在 node3(ecs-7b14-81c9-0003)独占执行;网络测试为 node3 → node2(192.168.0.x)内网。node1 曾因 sshd 加固事故临时下线,单节点数据以 node3 为准,已注明。
摘要 / 写在前面
监控告诉你“现在哪里堵了”,但基准测试告诉你“这台机器到底能跑多快”。两者是互补的:没有基线,你看到 CPU 100% 不知道是不是本来就慢;没有瓶颈定位,你跑出 8000 IOPS 不知道为什么上不去。
但基准测试也是被滥用最多的环节:很多人dd一下就敢说“磁盘 500MB/s”,iperf3跑一秒就敢写“网络 1Gbps”。结果到了生产,实际吞吐差了一个数量级。本篇要纠正的核心观念是:基准测试的价值不在那一个数字,而在“测试是否严谨”。
本篇覆盖四大类基准测试,全部用真实云主机跑出真实数字:
- CPU 算力:
sysbench跑素数,重点看线程扩展性(1/2/4/8 线程的吞吐量曲线),而不是只看单线程分。 - 磁盘 I/O:
fio测 4K 随机 IOPS 与 1M 顺序带宽,把libaio/iodepth/direct这些“玄学参数”讲透。 - 内存带宽:
mbw测 MEMCPY / DUMB / MCBLOCK 三种拷贝方式的带宽差异。 - 网络:
iperf3跑 TCP 与 UDP,对比吞吐与丢包,揭示“UDP 无拥塞控制”的真实代价。
每个测试我都把原始输出做成对比表,并解释每个参数是什么、为什么要这样设、数字背后意味着磁盘/CPU/网络受什么限制。读完你会知道怎么设计一次“可信”的基准测试,以及怎么从数字反推硬件瓶颈。所有数据均来自真实执行,未做任何编造。
一、为什么需要基准测试(原理先行)
1.1 基准测试解决三个问题
| 问题 | 没有基准测试 | 有基准测试 |
|---|---|---|
| 机器性能是否达标 | 凭感觉、被厂商宣传带偏 | 用真实负载验证规格书上的“8 vCPU / 高 IO” |
| 优化有没有效果 | 改了配置,不知道是变快还是变慢 | A/B 前后数值对比,量化收益 |
| 故障是硬件还是软件 | 数据库慢了先怀疑代码 | 先看 IOPS/带宽是否贴近基线,快速排除硬件 |
一个经典误区:把监控瞬时值当容量。比如某刻磁盘 %util=100%,你以为是磁盘满负荷,但其实可能是某个进程在串行单线程写,带宽只用了 30MB/s。只有基准测试能告诉你“这块盘理论上能到多少”,从而判断“现在是真满还是用法错”。
1.2 测试严谨性:多跑取稳定值、避免干扰
基准测试最大的敌人是噪声。云主机上至少有这些干扰源:
- 邻居噪声(noisy neighbor):同一宿主的其他租户在抢 CPU/IO,导致你每次跑结果浮动。
- 本机干扰进程:dockerd、containerd、监控 agent、定时任务(cron)都会偷走 CPU 和 IO。
- 页缓存污染:读测试前若不清 page cache,第二次读会全命中缓存,测的是内存不是磁盘。
- 采样时间太短:一个 1 秒的
iperf3可能正好撞上 GC 抖动,毫无代表性。
本篇的严谨做法(也是你应该养成的习惯):
- 每项测试跑多次取稳定值,本篇 sysbench 统一
time=15s、fio 统一runtime=30且time_based(跑满时长而非固定数据量,避免小文件秒完)。 - 关键测试加
direct=1(绕过 page cache,测真实设备)、conv=fdatasync(写测试强制落盘),避免“测得是内存不是磁盘”。 - 独占节点:node3 在测试期间不跑其他负载,CPU 实测
steal=0(见第 4 篇验证),保证结果干净。 - 预热(warm-up):FIO 的 iodepth 队列、TCP 的拥塞窗口都需要几秒建立,所以取稳态区间而非开头。
- 关注 P 分位而非均值:sysbench 看 95th percentile 延迟,因为均值会被“快的那批”拉低、掩盖长尾。
一句话:一次可信的基准测试 = 干净的隔离环境 + 正确的参数(direct/iodepth/time_based)+ 多次稳定采样 + 看长尾延迟。
1.3 真实案例:一次“假基准”如何误导选型
讲一个我见过的真实翻车:某团队用dd if=/dev/zero of=test bs=1M count=1000测新购的云盘,得到 “500 MB/s,盘很棒”,于是按这个盘规划了数据库容量。上线后数据库 TPS 却只有预期的 1/10。原因有三:①dd写的是/dev/zero,数据全零,云底层可能做了压缩/去重,落盘量被严重低估;②dd默认走 page cache,测的是内存不是盘;③ 数据库是 16K 随机写,而dd是 1M 顺序写,两者负载模型完全不对等。用本篇的fio --rw=randwrite --bs=16k --direct=1一测,真实 IOPS 只有几百——瓶颈一目了然。
这正说明:基准测试错配负载模型,比不测更危险,因为它给你一个“虚假的安全感”。选工具、选参数,必须贴合你的真实业务 IO 特征。
二、CPU 基准:sysbench 线程扩展性
2.1 命令与原理
sysbench cpu通过不断做素数计算(--cpu-max-prime)来压满 CPU,报告events per second(每秒完成的素数计算事件数,即吞吐)。素数判定是典型的计算密集、数据局部性好、几乎不访问内存的负载,所以它主要压的是CPU 整数运算单元和流水线,而非内存或 IO——这正好适合测“纯算力”和“多核扩展效率”。我们分别用 1/2/4/8 个线程跑,观察多核扩展性——这比单线程分有用得多,因为它直接反映“你的程序能不能吃满这台 8 vCPU 机器”。
2.2 真实结果与对比表
$fortin1248;doecho"--- threads=$t---"sysbench cpu --cpu-max-prime=20000--threads=$t--time=15run2>/dev/null|grep-E'Number of threads|events per second|total time:|Latency \(ms\)|95th percentile'done---threads=1--- Number of threads:1events per second:1629.83total time:15.0004s 95th percentile:0.62---threads=2--- Number of threads:2events per second:3265.00total time:15.0006s 95th percentile:0.62---threads=4--- Number of threads:4events per second:6521.04total time:15.0005s 95th percentile:0.62---threads=8--- Number of threads:8events per second:7195.86total time:15.0008s 95th percentile:1.12整理成对比表:
| 线程数 | 事件/秒 (eps) | 相对加速比 | 线性度(效率) | 95th 延迟 (ms) |
|---|---|---|---|---|
| 1 | 1629.83 | 1.00× | 100% | 0.62 |
| 2 | 3265.00 | 2.00× | 100% | 0.62 |
| 4 | 6521.04 | 4.00× | 100% | 0.62 |
| 8 | 7195.86 | 4.41× | 55.2% | 1.12 |
2.3 输出解读(看数字→定位瓶颈)
- 1→2→4 线程:完美线性扩展。1629 → 3265 → 6521,加速比 2.00× / 4.00×,效率 100%。这印证了第 4 篇
lscpu的结论:本机是4 个物理核(Core(s) per socket: 4)。每增加一个物理核,吞吐翻倍,没有任何争用。 - 4→8 线程:扩展性断崖。从 4 核到 8 逻辑线程(开启超线程,因为
Thread(s) per core: 2),吞吐只从 6521 涨到 7195,加速比仅 1.10×,效率掉到 55%。原因:8 个线程挤在 4 个物理核上,超线程的第二个逻辑核要共享执行单元、缓存和流水线,对“素数计算”这种计算密集、缓存友好的负载,超线程几乎帮不上忙,只带来 ~10% 边际收益。 - 95th 延迟同步恶化:1/2/4 线程都是 0.62ms,到 8 线程跳到 1.12ms(接近翻倍)。说明 8 线程时 SMT 资源争用拉长了尾延迟——吞吐量微涨,但每个事件的延迟变长,对延迟敏感场景其实是退步。
工程结论:
- 这台机器的“有效计算核”是4 个物理核。跑 CPU 密集服务(如编解码、压缩、加密),把 worker 数设成4通常最经济;设 8 只是徒增上下文切换和延迟。
- 如果你的程序是 CPU 密集且缓存友好(像 sysbench prime),超线程帮助有限,别盲目按逻辑核数开线程。
- 如果是 IO 密集或存在等待(syscall、锁),超线程才有较大收益——所以“线程数该怎么设”没有标准答案,要靠本篇这种扩展性测试来定。
三、磁盘基准:FIO 4K 随机 / 1M 顺序
3.1 参数含义(先懂参数再跑)
FIO 参数多到劝退,但基准测试里这几个是命门:
| 参数 | 含义 | 为什么重要 |
|---|---|---|
--rw | randread/randwrite/read/write | 随机还是顺序、读还是写,模拟不同负载 |
--bs | block size,如 4k / 1M | 4K 随机代表数据库/小文件(看 IOPS),1M 顺序代表大文件吞吐(看带宽) |
--ioengine=libaio | Linux 原生异步 IO | 真正压测磁盘并发能力,比同步sync引擎更贴近生产 |
--direct=1 | 绕过 page cache | 必须开,否则测的是内存不是磁盘 |
--iodepth=32 | 每个 job 的并发未完 IO 数 | 深度不够测不出磁盘峰值;32 是常见压测值 |
--numjobs | 并发进程/线程数 | 配合 iodepth 调并发度 |
--runtime=30 --time_based | 跑满 30 秒 | 取稳态,避免小文件秒完导致结果失真 |
--group_reporting | 合并多 job 报告 | 看总吞吐而非分散 |
3.2 真实结果(iodepth=32,direct=1,libaio)
$mkdir-p/root/fiotest $forrwinrandread randwritereadwrite;doforbsin4k 1M;doecho"---$rw$bs---"fio--name=$rw-$bs--rw=$rw--bs=$bs--ioengine=libaio--direct=1\--numjobs=1--iodepth=32--size=512M--runtime=30--time_based\--group_reporting--filename=/root/fiotest/testfile2>/dev/null|grep-E'READ|WRITE|IOPS|BW='donedone--- randread 4k --- read:IOPS=8053,BW=31.5MiB/s(33.0MB/s)(968MiB/30783msec)--- randread 1M --- read:IOPS=122,BW=122MiB/s(128MB/s)(3750MiB/30703msec)--- randwrite 4k --- write:IOPS=8068,BW=31.5MiB/s(33.0MB/s)(968MiB/30703msec);0zone resets --- randwrite 1M --- write:IOPS=122,BW=122MiB/s(128MB/s)(3750MiB/30703msec);0zone resets ---read4k --- read:IOPS=8067,BW=31.5MiB/s(33.0MB/s)(968MiB/30706msec)---read1M --- read:IOPS=122,BW=122MiB/s(128MB/s)(3751MiB/30720msec)---write4k --- write:IOPS=8168,BW=31.9MiB/s(33.5MB/s)(957MiB/30002msec);0zone resets ---write1M --- write:IOPS=122,BW=123MiB/s(129MB/s)(3730MiB/30401msec);0zone resets整理成对比表(取 IOPS 与带宽):
| 负载模式 | block size | IOPS | 带宽 (MiB/s) | 带宽 (MB/s) |
|---|---|---|---|---|
| randread | 4k | 8053 | 31.5 | 33.0 |
| randread | 1M | 122 | 122 | 128 |
| randwrite | 4k | 8068 | 31.5 | 33.0 |
| randwrite | 1M | 122 | 122 | 128 |
| read | 4k | 8067 | 31.5 | 33.0 |
| read | 1M | 122 | 122 | 128 |
| write | 4k | 8168 | 31.9 | 33.5 |
| write | 1M | 122 | 123 | 129 |
3.3 输出解读(看数字→定位瓶颈)
观察 1:随机与顺序几乎一样,读与写也几乎一样。
4K 随机读 8053 IOPS ≈ 4K 顺序读 8067 IOPS;随机写 8068 ≈ 顺序写 8168。这彻底排除了“机械盘”特征——传统 HDD 随机比顺序慢几十倍(寻道时间),而这里随机=顺序,说明底层是没有寻道开销的固态/分布式块存储(第 4 篇lsblk也显示是 virtio 云盘,rota=1是默认值不可信)。读写对称则说明存储对读和写一视同仁。
观察 2:4K 随机被 IOPS 限制,1M 顺序被带宽限制——这是两个独立的天花板。
- 4K 随机:8050 IOPS × 4KB =32 MB/s,远没到 128 MB/s。所以小 IO 的瓶颈是IOPS 上限 ~8000。
- 1M 顺序:122 IOPS × 1MiB =122 MiB/s≈ 128 MB/s。注意这里 IOPS 只有 122(因为每次 IO 是 1MiB 那么大),带宽是 122MiB/s。所以大 IO 的瓶颈是带宽上限 ~128 MB/s。
这就是一块典型的“双指标受限”云盘:小 IO 看 IOPS(约 8000),大 IO 看带宽(约 128 MB/s)。判断你业务受哪个限制,就看你的 IO 特征更接近哪头:数据库随机小包 → 卡在 8000 IOPS;大文件拷贝/日志批量写 → 卡在 128 MB/s。
观察 3:为什么 1M 顺序只有 122 IOPS?会不会测错了?
不是测错。因为bs=1M时每个 IO 本身就是 1MiB,IOPS = 带宽 / IO大小 = 128MB/s ÷ 1MB ≈ 122。要提升 1M 顺序带宽,得提高并发(--numjobs或多文件),让多个 1MiB IO 同时 in-flight,把 iodepth 用满。本测试numjobs=1 iodepth=32已能填满队列,128 MB/s 就是这块盘的单流上限。若要测多流聚合带宽,可加--numjobs=4。
生产经验:
- 评估数据库盘,认准4K 随机 IOPS(MySQL/PostgreSQL 的页通常是 4K/16K)。
- 评估日志/对象存储盘,认准1M 顺序带宽。
- 永远开
--direct=1和--time_based,否则你测的只是内存速度,会虚高 10~100 倍。 - 注意
IOPS和BW的自洽关系:BW(MiB/s) ≈ IOPS × bs(KiB) / 1024,可用来快速校验结果是否离谱。
3.4 深度:iodepth / numjobs 该怎么设,以及“好盘”该长什么样
很多人跑 fio 只会照抄--iodepth=32,却不知它和--numjobs共同决定“并发度”。iodepth 是单个 job 内的队列深度(异步 IO 能同时挂起多少个未完成的 IO),numjobs 是并行进程数,二者乘积是总并发在途 IO 数。本篇numjobs=1 iodepth=32已足够填满单流队列,所以测出的是“单流极限”。若要测多队列/多核聚合带宽,应加大 numjobs(如--numjobs=4 --iodepth=32,64 并发)。
那“好盘”应该是什么样?把本篇结果放进行业参照系:
| 盘类型 | 4K 随机 IOPS | 1M 顺序带宽 | 对照本机 |
|---|---|---|---|
| 机械盘 HDD | 100~200 | 100~200 MB/s | 远超(本机无寻道) |
| 普通云盘(本机这类) | ~8000 | ~128 MB/s | 即本机 |
| 云 SSD(高 IO 型) | 数万~十万+ | 数百~数千 MB/s | 本机差一个数量级 |
| 本地 NVMe | 数十万 | 数 GB/s | 本机差两个数量级 |
结论:本机磁盘属于“够用但非高性能”的入门级云盘——随机 IOPS 8000、带宽 128 MB/s。它适合系统盘、轻量应用、开发测试;不适合做高并发数据库主存储或大规模日志写入(会先撞上 8000 IOPS 或 128 MB/s 天花板)。选型时,若业务是 IOPS 敏感型,必须升级到高 IO 型云盘,否则再怎么调应用参数也突破不了这个硬件上限。这也是基准测试最大的价值:在花钱之前,先用数字确认硬件能不能扛住你的业务。
四、内存带宽:mbw
4.1 原理与命令
mbw通过三种不同方式把一块内存拷贝到另一块,测量内存带宽(MB/s):
- MEMCPY:标准 libc
memcpy()。 - DUMB:逐字节/逐字手动复制(最朴素)。
- MCBLOCK:按 block 大块复制(通常借助优化指令)。
$ mbw2562>/dev/null|grep-iE'AVG|MEMCPY|MOVEDOUBLE'|tail-67Method: MEMCPY Elapsed:0.01662MiB:256.00000Copy:15403.129MiB/s8Method: MEMCPY Elapsed:0.01653MiB:256.00000Copy:15491.679MiB/s9Method: MEMCPY Elapsed:0.01661MiB:256.00000Copy:15415.186MiB/s AVG Method: MEMCPY Elapsed:0.01661MiB:256.00000Copy:15412.031MiB/s AVG Method: DUMB Elapsed:0.01612MiB:256.00000Copy:15880.992MiB/s AVG Method: MCBLOCK Elapsed:0.01330MiB:256.00000Copy:19246.384MiB/s4.2 结果对比表
| 拷贝方法 | 平均带宽 (MiB/s) | 相对 MEMCPY |
|---|---|---|
| MEMCPY | 15412 | 1.00× |
| DUMB | 15880 | 1.03× |
| MCBLOCK | 19246 | 1.25× |
4.3 输出解读
- 内存带宽高达15~19 GiB/s,这是双通道 DDRx 的典型表现。和本机 CPU 内存控制器、NUMA(单节点)配置相符。
- MCBLOCK 比 MEMCPY 快约 25%(19246 vs 15412 MiB/s),因为它用更大的块/向量指令批量搬运,减少了循环开销——说明“怎么拷”能带来可观差异,也提示你:自己写的内存拷贝热点,用
memcpy而非手写循环通常更优(编译器会选最好的实现)。 - DUMB 反而略快于 MEMCPY,属于测量噪声(256MiB 太小、测 3 次波动),大块测试下 MCBLOCK 优势稳定。
- 这个值怎么用:内存带宽基准告诉你“内存墙”在哪。如果你的应用(如内存数据库、大矩阵运算)实测吞吐远低于 15GiB/s,通常不是内存 itself 的锅,而是缓存命中率低 / 访存模式不连续导致的“有效带宽”不足——这时该优化数据局部性,而不是怪内存慢。
4.2 补充:内存带宽与 CPU 缓存层级的关系
本机lscpu显示 L1d/L1i 各 128KiB、L2 4MiB、L3 32MiB。mbw 测的 15~19 GiB/s 是跨内存通道的聚合带宽,而真正决定程序快慢的是更靠近 CPU 的缓存:L1 带宽可达数百 GB/s、L3 也有几十 GB/s,都比内存快一个数量级。所以内存带宽基准的意义在于“兜底”——它确认内存子系统不是瓶颈;若程序仍慢,瓶颈一定在缓存命中率、分支预测或算法复杂度上,而非硬件内存带宽。换句话说,内存带宽是“及格线”,不是“加速剂”,优化应优先聚焦缓存友好性。
五、网络基准:iperf3 TCP / UDP
5.1 拓扑与命令
网络基准需要一个服务端(接收)和一个客户端(发送)。本测试:
- 服务端跑在 node2(内网 192.168.0.x),
iperf3 -s监听。 - 客户端在 node3(ecs-7b14-81c9-0003),向 node2 打流。
这样测的是两台云主机之间的内网带宽,比本地回环(lo)更有生产意义。
5.2 TCP 测试结果
$ iperf3-c192.168.0.9-t20-fM2>/dev/null|grep-E'sender|receiver'[5]0.00-20.00 sec14.3GBytes733MBytes/sec47817sender[5]0.00-20.00 sec14.3GBytes733MBytes/sec receiver输出解读:20 秒共传14.3 GBytes,平均733 MBytes/sec(约 5.9 Gbps)。sender 与 receiver 数值完全一致(47817 是 sender 端的某种计数标识),说明零丢包、TCP 可靠交付,内网 TCP 吞吐稳定在 ~733 MB/s。这就是该规格云主机内网的理论带宽水平。
5.3 UDP 测试结果(经典翻车现场)
$ iperf3-c192.168.0.9-u-b0-t10-fM2>/dev/null|grep-E'sender|receiver|Jitter'[5]0.00-10.00 sec3.98GBytes408MBytes/sec0.000ms0/2953970(0%)sender[5]0.00-10.00 sec3.66GBytes375MBytes/sec0.002ms240504/2953966(8.1%)receiver输出解读(这是 UDP 最该被记住的一课):
- 客户端(
sender)以-b 0(不限速,尽力狂发)打出了408 MBytes/sec,声称 0 丢包(0/2953970)——但注意,sender 的“0 丢包”只是说“我全发出去了”,不代表对面全收到了。 - 接收端(
receiver)只收到375 MBytes/sec,且丢了 240504 / 2953966 个数据报 = 8.1% 丢包,抖动(Jitter)仅 0.002ms(内网本身很稳定,延迟没问题)。 - 根因:UDP 没有拥塞控制,客户端不看接收端死活一味猛发,瞬间打满链路,交换机/网卡缓冲区溢出 → 丢包。UDP 的“高吞吐”是以牺牲可靠性换来的。
5.4 TCP vs UDP 对比表
| 指标 | TCP (-b默认) | UDP (-b 0不限速) |
|---|---|---|
| 发送速率 | 733 MB/s | 408 MB/s |
| 接收速率 | 733 MB/s | 375 MB/s |
| 丢包率 | 0% | 8.1% |
| 抖动 | — | 0.002 ms |
| 可靠交付 | 是(重传保证) | 否(应用层自管) |
工程结论:
- TCP 测的是“你能稳定用到的带宽”(733 MB/s),这是你业务能指望的上限。
- UDP 的发送速率数字会骗人:408 MB/s 是“发出去的”,375 MB/s + 8.1% 丢包才是“实际有效吞吐”。评估 UDP 应用(音视频、游戏、QUIC),必须看 receiver 的丢包率,并据此在应用层限速 / 加重传 / 加 FEC。
- 若想测 UDP “不丢包时的最大吞吐”,应逐步调大
-b直到 receiver 丢包率接近 0,那个-b值才是 UDP 可用带宽。直接-b 0只会得到漂亮的发送数和难看的丢包率。
5.5 进阶:为什么单流只有 733 MB/s,以及如何测出更高带宽
你可能会疑惑:云主机内网标称通常不是更高吗?这里有两个常见影响因素,基准测试时要心里有数:
- 单 TCP 流受窗口与 RTT 限制:单条 TCP 连接的吞吐上限 ≈
窗口大小 / RTT。内网 RTT 极低(亚毫秒级),但单流仍可能卡在某个内部限速或单核软中断处理上。若要压榨整机带宽,应开多并行流:iperf3 -c 192.168.0.9 -P 8(8 个并发连接),聚合带宽往往能数倍于单流。本篇单流 733 MB/s 是“单连接保底”,多流可评估网卡聚合能力。 - 软中断(softirq)可能成为瓶颈:高带宽下,收包软中断会集中在一个 CPU 上。若
mpstat看到某核%soft飙高而其他核空闲,就是 IRQ 亲和性没打散,可通过irqbalance或手动smp_affinity把网卡中断分散到多核,释放更多带宽。这也呼应了第 4 篇的%soft指标——基准测试时顺手看一眼软中断分布,能解释“为什么带宽上不去”。
六、避坑 & 调优建议
- 永远用
direct=1+time_based跑磁盘基准,否则 page cache 让你“测内存不测盘”,数值虚高。 - CPU 基准要看扩展性曲线,不只看单线程分。本机 4 物理核线性扩展,超线程只 +10%,线程数设 4 最划算。
- 区分 IOPS 受限与带宽受限:4K 看 IOPS(~8000),1M 看带宽(~128 MB/s)。用
IOPS × bs自洽校验结果。 - iperf3 网络测试要在两台机器间打、且看 receiver 端。
-b 0跑 UDP 必丢包,那不是网络差,是 UDP 没拥塞控制。 - 多次采样取稳定值:sysbench 用
--time=15、fio 用--runtime=30,避开启动抖动;报告里带 95th 延迟而非只看均值。 - 隔离干扰:基准测试期间尽量独占节点,关掉 cron、限制 docker 容器;否则邻居噪声会让数字浮动。
- fio 的 IOPS 与 BW 单位要认清:
MiB/s是 2^20 字节,MB/s是 10^6 字节,差 ~4.8%,写报告时统一口径避免被挑刺。 - 别用 dd 当磁盘基准:
dd是顺序大块、走缓存、单线程,只能粗略看顺序写,测不出 IOPS。要科学请用 fio。
七、小结
- 基准测试的核心不是数字,是“严谨”:干净环境 + 正确参数(direct/iodepth/time_based)+ 多次稳定采样 + 看长尾延迟。
- CPU(sysbench):1/2/4 线程完美线性(效率 100%),4→8 线程仅 +10%(超线程对计算密集负载帮助有限)。有效计算核 = 4 个物理核,线程数设 4 最经济。
- 磁盘(fio):4K 随机 IOPS ≈ 8050(受 IOPS 限制),1M 顺序带宽 ≈ 128 MB/s(受带宽限制);随机=顺序、读=写,确认是固态/分布式存储。IOD 受限与带宽受限是两个独立天花板。
- 内存(mbw):带宽 15~19 GiB/s,MCBLOCK > MEMCPY > DUMB,提示用优化拷贝优于手写循环。
- 网络(iperf3):内网 TCP 稳定 733 MB/s(~5.9 Gbps)零丢包;UDP
-b 0发送 408 MB/s 但 receiver 丢 8.1%——揭示 UDP 无拥塞控制的真实代价,应用层必须自管速率/重传。 - 看数字→反推瓶颈:IOPS 与
IOPS×bs是否等于带宽,可以判断磁盘卡在哪一环;CPU 扩展效率断崖点暴露物理核数;UDP 收发两端速率差就是链路饱和丢包。 - 所有数据来自 node3 真实云主机(node1 曾临时下线,单节点以 node3 为准),未做任何编造。
八、从基准到上线:一张容量规划速查表
基准测试跑完,下一步是“用数字做决策”。把本篇四类结果翻译成可执行的规划动作:
| 基准项 | 本机实测 | 含义 | 规划动作 |
|---|---|---|---|
| CPU 有效核 | 4 物理核(超线程 +10%) | 8 逻辑核不等于 8 倍算力 | 计算密集服务 worker 设 4;IO 密集可设 8 |
| 4K 随机 IOPS | ~8000 | 数据库小 IO 天花板 | IOPS 敏感业务需升级高 IO 云盘,否则 TPS 卡在此 |
| 1M 顺序带宽 | ~128 MB/s | 大文件吞吐天花板 | 日志/备份吞吐按 128 MB/s 估,别按厂商宣传值 |
| 内存带宽 | 15~19 GiB/s | 内存墙极高,非瓶颈 | 重点优化缓存命中率而非担心内存速度 |
| 内网 TCP | 733 MB/s | 单流稳定带宽 | 跨节点同步/备份按此估;高吞吐用多并行流 |
| UDP 可用 | 408 发 / 375 收 / 丢 8.1% | 无拥塞控制会丢包 | UDP 业务必须应用层限速+重传/FEC |
最重要的原则:基准测试不是为了炫耀数字,而是为了在生产事故发生前,先知道硬件的上限在哪。当某天数据库变慢,你拿出这张表一对照——“当前 IOPS 7800,已经贴近 8000 上限”——立刻就能判断是磁盘到了天花板、该扩容,而不是盲目去翻代码。这就是基准测试真正的工程价值。
最后提醒一句:本篇所有数字都是这台具体机型、这块具体云盘的快照。云厂商不同规格、不同可用区、甚至不同时段的邻居负载都会让结果浮动,所以基准报告一定要标注“机型 + 日期 + 测试条件”,且每隔一段时间复测一次,你手里的容量基线才不会过期失真。
附:本文实验环境 / 一键复现脚本
实验环境:华为云 4 节点 ECS,Ubuntu 24.04.4 LTS,内核6.8.0-106-generic,8 vCPU(4 物理核 × 2 超线程)/ ~14.8 GiB,KVM 全虚拟化。
- CPU / 磁盘 / 内存基准:node3(ecs-7b14-81c9-0003,公网 120.46.x.x)独占。
- 网络基准:node3(客户端)→ node2(服务端,内网 192.168.0.x)。
依赖安装:
sudoapt-getupdate-qqsudoapt-getinstall-ysysbench fio mbw iperf3服务端(node2)先起:
iperf3-s-D# 后台监听 5201一键复现脚本(node3 执行):
#!/usr/bin/env bash# 05-bench-all.sh —— 复现本篇全部基准测试set-uexportDEBIAN_FRONTEND=noninteractiveecho"===== [sysbench CPU] 线程 1/2/4/8 ====="fortin1248;doecho"--- threads=$t---"sysbench cpu --cpu-max-prime=20000--threads=$t--time=15run2>/dev/null|\grep-E'Number of threads|events per second|total time:|95th percentile'doneecho"===== [FIO] 4K随机 / 1M顺序, iodepth=32, direct=1 ====="mkdir-p/root/fiotestforrwinrandread randwritereadwrite;doforbsin4k 1M;doecho"---$rw$bs---"fio--name=$rw-$bs--rw=$rw--bs=$bs--ioengine=libaio--direct=1\--numjobs=1--iodepth=32--size=512M--runtime=30--time_based\--group_reporting--filename=/root/fiotest/testfile2>/dev/null|grep-E'READ|WRITE|IOPS|BW='donedonerm-rf/root/fiotestecho"===== [mbw] 内存带宽 ====="mbw2562>/dev/null|grep-iE'AVG'|tail-3echo"===== [iperf3] 内网 TCP (node3 -> node2 192.168.0.x) ====="iperf3-c192.168.0.9-t20-fM2>/dev/null|grep-E'sender|receiver'echo"===== [iperf3] 内网 UDP ====="iperf3-c192.168.0.9-u-b0-t10-fM2>/dev/null|grep-E'sender|receiver|Jitter'echo"BENCH_DONE"说明:iperf3 服务端 IP
192.168.0.9为本文 node2 内网地址(已按规范保留为 192.168.0.x)。FIO 测试会生成约 512MiB 临时文件,脚本已自动清理。所有输出与本篇一致,可直接对照验证。