POSIX API 基准测试
Fio (Flexible I/O Tester) 是一款功能强大的开源存储系统基准测试工具。由于 Alluxio 可以通过 FUSE 挂载为符合 POSIX 标准的文件系统,fio 非常适合用于测量其读/写 IOPS 和吞吐量。
如何阅读本指南:
多节点 / 大集群调优——跑完单节点之后,继续阅读 进阶:横向扩展基准。覆盖两种文件访问模式、
fio --server/--client、多 worker 扩展、200 Gbps 参考数据。
开始之前
客户端节点指运行 fio 并挂载 Alluxio FUSE 文件系统的机器(或 Pod)。Kubernetes 部署下这是一个挂载了 FUSE PVC 的应用 Pod——Pod 配置见 POSIX API。跑任何基准命令之前,确认下列项都满足。
基准测试准备
生成测试数据
使用 fio 本身通过 FUSE 挂载写入测试文件,把数据持久化到 UFS。注意:Alluxio 默认写类型是 THROUGH(写时不缓存),所以这一步不会自动把数据放入 Alluxio 缓存——做热缓存读测试前,需要先执行准备缓存状态里的 alluxio job load 步骤。
准备缓存状态
每次读取基准前,控制缓存状态以隔离你实际要测量的对象。
每次读取测试前务必清掉 FUSE 侧的内核 page cache。
在下面的每一次热缓存和冷缓存基准之前都要在客户端节点上执行一次。
热缓存(测量 Alluxio 缓存命中性能):
fio 写入默认会走 UFS 但不入 Alluxio 缓存,所以必须显式加载。提交 load 作业后轮询 --progress 直到 Job State 报告 SUCCEEDED(视数据集大小,通常需要几秒到几分钟):
冷缓存(测量后端拉取 + 缓存填充性能):
参数与测试设计
固定参数
整个扫描中保持一致,保证结果可比。
ioengine(推荐:io_uring,或libaio作 fallback)—— Linux 异步 I/O 后端。io_uring(内核 5.1+)吞吐更高、延迟更低。direct(推荐:1)—— 在 open 时请求O_DIRECT,绕过客户端 page cache。group_reporting(推荐:始终设置)—— 把各线程结果聚合成一个摘要。runtime(推荐:60)—— 每步 60 秒足以达到稳态,同时不会让整个扫描拖太长。
控制参数
根据你要测量的内容调整。
rw—— I/O 模式。read测顺序吞吐;randread测随机 IOPS。bs—— 块大小。吞吐测试用256K 到 1M,IOPS 测试用4k。不要超过1M——过大的块(4M+)会减少 op 数、引入队头阻塞,掩盖存储栈真实的吞吐特征。numjobs—— 并发 I/O 线程数。从1开始向上扫(1、2、4、8、16、32、64、128、256、512)。选 p99 延迟拐点处的值,而不是 BW 数值峰值处——p99 会先于吞吐劣化。iodepth—— 每线程未完成 I/O 数。1是典型值;32配合"每线程钉一个文件"的做法用于最大化单线程吞吐。两者的权衡见 两种文件访问模式。size—— 每个测试文件的大小。
选择文件布局
测试文件的数量是最重要的设计选择之一——它决定你实际测到的是哪个上限。
单个大文件(例如一个 100 GiB 文件)。测单文件吞吐,由 Alluxio FUSE per-file 串行化决定。用于快速验证、确认单文件能达到的上限。
多个文件(例如 10-20 个 5-10 GiB 的文件)——推荐用于正式基准测试。测集群/worker 的吞吐上限,每个文件由独立的 stream 服务。峰值通常比单文件高 10-15%。
大量小文件(例如 100+ 个)。近似 AI/ML 训练的 I/O 模式,涉及 handle 管理与元数据操作。测峰值吞吐时,优先选用上面的"多个文件"方案。
测多文件时,先用 fio 生成文件,然后用冒号分隔的列表传给 fio:
fio 以 round-robin 方式把 job 分配到各文件——文件数应 ≥ numjobs,否则又会退回到 per-file 锁竞争。
多 worker 或多 client 场景下值得跑两种互补的文件访问模式——见进阶章节的 两种文件访问模式。
基准命令
顺序读吞吐
✅ 成功: 查看输出中的 BW(带宽)。使用下文硬件、32 线程、热缓存的情况下,预期 ~9 GiB/s。
随机读 IOPS
✅ 成功: 查看输出中的 IOPS。使用下文硬件、32 线程、热缓存的情况下,预期 ~70k IOPS。
并发扩展
要找到吞吐量上限,使用递增的 --numjobs 重复运行同样的命令:
解读扫描结果:
若
numjobs翻倍后BW不再增长,说明已经触到瓶颈(网络、磁盘或 CPU)。P99 比 BW 更早劣化。 一旦 BW 不再线性扩展,看一眼
clat 99.00th——如果它已经明显上涨,就已经过了 sweet spot。选numjobs应选拐点处的值,而不是数值峰值处。
解读结果
典型的 fio 输出:
阅读方式:
BW
所有线程聚合吞吐
吞吐测试的主指标
IOPS
每秒 I/O 操作数
IOPS 测试的主指标
clat avg
平均完成延迟
越低越好;高值提示有竞争
clat 99.00th
P99 尾延迟
该指标飙升代表性能抖动
CPU % per GB/s
FUSE 栈的 CPU 效率(top CPU% ÷ BW)
高值说明 worker 上 FUSE 线程或 JVM 开销偏高
经验法则:
若
clat P99超过avg的 10 倍,排查尾延迟来源(GC 暂停、UFS 回退、FUSE 线程饥饿)。冷缓存吞吐量通常比热缓存低 10-50 倍。差距较小时,"热"测试可能因缓存加载不充分而打到了 UFS。
基线结果
下文给出的是单节点 NVMe 基线数据。面向 200 Gbps 实例的多节点高吞吐数据见进阶章节的 200 Gbps DRAM 横向扩展基线。
只展示读结果。Alluxio 默认的 write-through 策略在写入时会绕过缓存,所以 fio 测到的写吞吐反映的是 UFS 性能,不是 Alluxio 缓存性能。要测 Alluxio 加速的写性能,先启用并调优写缓存——见 S3 写入缓存。
单节点 NVMe 基线
采集环境:
Alluxio Worker 节点:AWS
i3en.metal,8 块 NVMe SSD 组成 RAID 0,Ubuntu 24.04Alluxio Client 节点:AWS
c5n.metal,Ubuntu 24.04,FUSE 3.16.2+单 worker、单 client、热缓存、单个 100 GiB 文件,所有实例位于同一个 AWS 可用区。
吞吐量(1M 块大小)
顺序读取
2101 MiB/s
9519 MiB/s
8089 MiB/s
随机读取
202 MiB/s
6684 MiB/s
8276 MiB/s
IOPS(4k 块大小)
顺序读取
55.9k
253k
192k
随机读取
2.3k
70.1k
162k
128 线程下顺序读吞吐量下降,说明客户端节点的 CPU 已经饱和。这是预期行为——最优并发度取决于具体硬件。
故障排查
基准运行时遇到的大多数读取路径问题——UFS fallback、缓存没 warm、FUSE 挂载选项调优、尾延迟尖刺——都是通用的 FUSE 问题,不是 benchmark 特有的。权威的排查流程在 POSIX API 文档里:
吞吐不随 numjobs 扩展
numjobs 扩展可能原因: Client 主机上的网络或 CPU 瓶颈。
诊断方式: 参见 POSIX API → 性能 → 判断卡在哪一层,按症状定位到对应层。
清理
完成基准测试后,清理测试数据并释放缓存条目。下面的通配符同时覆盖单文件布局(100gb)和多文件布局(file00..file19)。
进阶:横向扩展基准
本章覆盖的是从"单 FUSE client、单 worker"扩展到"多 worker、多 client"时要改变的那些东西。请先完成上面的单节点流程。
两种文件访问模式
两种互补的并发驱动方式,各自对应一类真实的访问模式。两种都跑,取较高 peak 作为集群 headline 上限。哪种模式贴近你生产负载,就是你需要对着调优的那一种。
共享文件模式—— 多个线程并发读同一组文件。对应"文件跨客户端共享"或"数据 locality 未知"的工作负载(多租户共享读)。
独立文件模式—— 每个线程(或小线程组)钉到自己的文件上并带深队列。对应 sharded 工作负载——典型例子是 AI 训练数据流水线,每个 GPU worker 读自己那份 data shard。
模式
iodepth
文件分布
Peak numjobs
共享文件
1
所有线程读所有文件
较高(32–256)
独立文件
32
每个文件由一个线程组独占
较低(4–16)
iodepth=1 下每线程只有一个未完成 I/O,并发靠加线程数来扩,所以共享文件模式在高 numjobs 达峰。iodepth=32 下单线程钉一个文件就能吃掉相当大一块带宽;独立文件模式在低 numjobs 达峰,再往上 queue depth 翻倍只会让 latency 飙升、吞吐不再涨。
共享文件命令——单一 fio section,所有线程共享同一组冒号分隔的文件列表:
独立文件命令——用多 section 的 fio job file,每个 section 独占一个或多个文件。按 numjobs 和文件数的关系生成 job file:
numjobs ≤ num_files→numjobs个 section,每个numjobs=1,文件 round-robin 分配。numjobs > num_files→num_files个 section,每个numjobs=numjobs/num_files,各钉一个文件。
常见情形(nj ≤ num_files)的生成示例:
扩展到多个 Client
典型的横向扩展顺序:先上一个 FUSE client,再加更多 FUSE client 把集群打到饱和,打满一个 worker 的上限后再加 Alluxio worker。当一个 client 无法驱动到实测的单 worker 上限时,切换到多 FUSE client 节点。
fio 自带分布式模式。先在每个 FUSE client 节点上启动 fio --server,再从 controller 发起作业:
所有 client 的结果会聚合成一个总摘要。解析时要注意:fio --client 的 JSON 把各主机结果放在 client_stats[] 下,而非单节点模式的 jobs[]。聚合方式:BW 按 sum 累加、latency 按 total_ios 加权平均。
fio --server / --client 的三个坑:
pkill fio会把 SSH 会话也一并 kill 掉(如果你是用同一个用户 SSH 进来的)。清理时用pkill -f 'fio --server'或按 PID kill。--daemonize模式会 hang。按上面用nohup ... &。host_list.txt用私网 IP,不要用公网域名——公网路径会让带宽远低于 VPC spine。
扩展到多个 Worker
增加 Alluxio worker 时,在低到中等并发下接近线性扩展,numjobs 继续涨时效率逐步下降。下文 xW/yC 记号表示 x 个 Alluxio worker × y 个 FUSE client 节点(例如 3W/3C = 3 worker + 3 client):
3W/3C
所有 numjobs 下约 ~96%
所有 numjobs 下约 ~96%
10W/10C
numjobs ≤ 16 时 99–121%,numjobs ≥ 32 降到 48–80%
绝大多数 numjobs 下 ~86–99%
10W/10C 高并发下共享文件模式效率掉得明显,是 FUSE file-level 锁竞争 造成的:太多线程打在太少的共享文件上。如果在 10+ worker 下跑共享文件模式,把文件数从本指南默认的 20 加到 100+,能把上限往上推。独立文件模式受此影响较小,因为每个线程组独占文件。
长时间基准的保护。 两种模式在 1W → 3W → 10W 全扫一遍要几小时,会跨多个 SSH 超时。把驱动脚本用 nohup + trap '' HUP 包起来放到后台,让它扛得住断线:
200 Gbps DRAM 横向扩展基线
采集环境:
Worker / Client / Coordinator:AWS
r6in.32xlarge(128 vCPU、1024 GiB RAM、200 Gbps ENA),Ubuntu 22.04,Alluxio AI-3.8-15.1.2Page store:DRAM 在独立 tmpfs 上(每 worker 300–500 GiB)
数据集:20 × 10 GiB 文件(共 200 GiB),后端 S3,已通过
alluxio job load预加载FIO:块大小 256 KiB、
io_uring引擎、direct=1、每步 60 秒
顺序读吞吐 peak:
1W/1C
14.0 / 111.8
14.4 / 115.3
3W/3C
37.6 / 300.4
41.5 / 331.6
10W/10C
89.7 / 717.3
131.3 / 1050.0
共享文件的 peak 在 numjobs=256(1W/1C、3W/3C)或 numjobs=32(10W/10C)达到。独立文件在所有拓扑下都是 numjobs=8 达峰。
Peak 相对 NIC 带宽的预期。 一个调优良好的 FUSE client,在 DRAM page store 命中时,一般能达到 每节点 NIC 带宽的 55–65%——200 Gbps NIC 就是约 14 GiB/s 每 client,再叠加 client 数量。如果你单 client 离这个数值明显差距较大,在怀疑 worker 或 UFS 瓶颈之前,先检查 JVM 堆/直接内存配置以及 FUSE mount options(max_idle_threads、max_background)。上表里 10W/10C 的数据是在没有 cluster placement group 的情况下测的——同 AZ 内的 VPC spine 带宽在这个规模下一般就够了。基本的网络 placement 指引对每次基准测试都适用,在 开始之前 里已经覆盖。
参见
通过 FUSE 的 POSIX API——FUSE 挂载配置与调优(包括 mount options 表格)
fio 官方文档——所有 fio 参数和 ioengine 的完整参考
Last updated