POSIX API 基准测试

Fio (Flexible I/O Tester) 是一款功能强大的开源存储系统基准测试工具。由于 Alluxio 可以通过 FUSE 挂载为符合 POSIX 标准的文件系统,fio 非常适合用于测量其读/写 IOPS 和吞吐量。

如何阅读本指南:

  • 单节点评估——从 开始之前 读到 清理 即可。覆盖一个 FUSE client 对单个 Alluxio worker 的场景。

  • 多节点 / 大集群调优——跑完单节点之后,继续阅读 进阶:横向扩展基准。覆盖两种文件访问模式、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 步骤。

准备缓存状态

每次读取基准前,控制缓存状态以隔离你实际要测量的对象。

热缓存(测量 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.04

  • Alluxio Client 节点:AWS c5n.metal,Ubuntu 24.04,FUSE 3.16.2+

  • 单 worker、单 client、热缓存、单个 100 GiB 文件,所有实例位于同一个 AWS 可用区。

吞吐量(1M 块大小)

带宽/线程
单线程
32 线程
128 线程

顺序读取

2101 MiB/s

9519 MiB/s

8089 MiB/s

随机读取

202 MiB/s

6684 MiB/s

8276 MiB/s

IOPS(4k 块大小)

IOPS/线程
单线程
32 线程
128 线程

顺序读取

55.9k

253k

192k

随机读取

2.3k

70.1k

162k

128 线程下顺序读吞吐量下降,说明客户端节点的 CPU 已经饱和。这是预期行为——最优并发度取决于具体硬件。

故障排查

基准运行时遇到的大多数读取路径问题——UFS fallback、缓存没 warm、FUSE 挂载选项调优、尾延迟尖刺——都是通用的 FUSE 问题,不是 benchmark 特有的。权威的排查流程在 POSIX API 文档里:

吞吐不随 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_filesnumjobs 个 section,每个 numjobs=1,文件 round-robin 分配。

  • numjobs > num_filesnum_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.2

  • Page 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:

拓扑
共享文件 peak(GiB/s / Gbps)
独立文件 peak(GiB/s / Gbps)

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_threadsmax_background)。上表里 10W/10C 的数据是在没有 cluster placement group 的情况下测的——同 AZ 内的 VPC spine 带宽在这个规模下一般就够了。基本的网络 placement 指引对每次基准测试都适用,在 开始之前 里已经覆盖。

参见

Last updated