一文解锁 JuiceFS 在 AI 场景中的性能优化
从架构看 JuiceFS 的性能基础
JuiceFS 分为社区版与企业版,二者整体架构一致,均采用元数据与数据分离的存储架构。客户端采用富客户端设计,承载包括部分元数据处理在内的多项核心逻辑,并同时提供元数据缓存与数据缓存能力,各模块协同工作以实现数据的高效定位与访问。底层数据存储基于对象存储构建,并可借助本地缓存进一步提升访问性能。对外接口上,JuiceFS 支持多种接入方式,其中 FUSE 最为常用,同时也兼容各类 SDK 与 S3 网关。
社区版定位为通用文件系统,用户可根据需求选择不同的元数据引擎。小规模部署可选择 Redis,实现轻量、高响应的数据管理;大规模文件场景可选择 TiKV,以获得良好的横向扩展能力。(参考:JuiceFS 元数据引擎选型指南)
企业版面向复杂高性能场景,相较于社区版,最大的差异有两方面:企业版采用自研多分区元数据引擎,基于 Raft 构建纯内存集群,延迟低且横向扩展能力强,可支持 5,000 亿文件规模。相比社区版需多次 KV 请求完成的操作,企业版通常仅需一次或两次,并可在元数据集群内部处理复杂逻辑。其次,企业版支持分布式缓存共享:同组客户端可在同一区域内互访本地缓存,基于一致性哈希实现,提高缓存命中率和访问效率。在多节点高并发场景下,缓存空间可横向扩展,任务执行前可预热大部分所需数据,从而加速 AI 训练与推理,提高系统性能和稳定性。(JuiceFS 企业版 5.3 特性详解:单文件系统支持超 5,000 亿文件,首次引入 RDMA)

数据分块设计
JuiceFS 将数据切块后存储于对象存储,这一设计是其提升性能的关键,将影响数据读取效率、缓存命中率及高并发访问下的吞吐能力。
JuiceFS 会将文件拆分为多个 chunk。在每个 chunk 内部,系统维护管理结构 slice,用于跟踪数据写入和更新。当文件发生写入时,新数据不会覆盖已有 slice,而是以新的 slice 追加到 chunk 上层。

理想情况下,每个 chunk 最终只应包含一个 slice。每个 slice 由若干 4 MB 的 block 组成,这些 block 是最终存储到对象存储的最小单元。默认情况下,缓存系统也以 block 为单位进行管理。

从右上方示意图可以看出,文件更新采用追加式写入:红色部分为已有 slice,新数据以新的 slice 叠加。读取时,系统组合各层 slice 形成当前视图;碎片过多时,再通过 compaction 合并,以优化访问性能。更多关于数据分块的细节可参考文档。
缓存体系
相较于直接访问对象存储,JuiceFS 的性能提升在很大程度上得益于其缓存体系。JuiceFS 客户端配备了高性能的本地缓存模块,与之相关的配置项如下:
cache-dir:用于指定缓存目录;cache-size:用于设定用于缓存的空间大小;prefetch:这是缓存模块中的一个参数,负责预取功能。当某一请求命中某个 block 时,会启动一个后台线程,将整个块完整拉取下来;write back相关配置:用于提高写 IOPS,将需要上传至对象存储的数据块,先写入本地缓存,再异步上传至对象存储。
企业版还具备一些进阶配置,例如通过 cache group 指定一批客户端,将它们的本地缓存配置为同一个分布式缓存组,实现缓存数据的共享。此外,no sharing 是与缓存组相关的配置,启用 no sharing 后,客户端仅从指定的缓存组读取数据,但不作为缓存组成员提供数据读取服务。如此一来,便形成了两级缓存:第一级是本地缓存,第二级是缓存组中其他节点上的缓存。
另一个提升性能的机制是内存 buffer(读 buffer),具有以下作用:
- 合并 IO 请求:可内存层面合并多个连续的 IO 请求。例如,系统发出三个 IO 请求,经内存缓存处理后,实际发出的可能仅有一个;
- 自适应预读功能:在大文件顺序读取场景下,自适应预读功能通过预读来提升请求并发度,从而充分利用缓存和对象存储资源,提高整体 I/O 性能。
企业版还有一些进阶配置:
max read ahead:用于设定预读的最大范围。initial read ahead: 用于设置开启预读时的预读窗口大小,默认以 4MB 块为单位。read ahead ratio: 是去年新增的配置,用于控制大文件随机读取时的预读比例,减少读放大导致的带宽瓶颈。过于激进的预读可能对随机读取性能产生负面影响,read ahead ratio可用于缓解该问题。在 AI 场景中,遇到大文件顺序或随机访问导致的带宽或 IOPS 瓶颈时,可通过调整这些参数优化整体性能。
02 JuiceFS 基准 I/O 测试与瓶颈分析
在介绍 JuiceFS 在常见 AI 场景下的性能调优之前,先通过连续读和随机读基准测试观察系统在理想条件下的 I/O 表现,以理解不同访问模式下的吞吐量与延迟,为后续 AI/ML 场景的读写模式提供参考。
连续读性能
在 JuiceFS 中,连续读的性能通常主要受带宽因素影响。在冷读场景下,性能主要受对象存储带宽约束;而在分布式缓存场景下,网络带宽可能成为瓶颈。例如,一台配备 40 Gbps 网卡的机器,其实际可用带宽可能不足 5 Gbps。此外,FUSE 层的用户态与内核态转换开销也会限制单线程吞吐,经测试单线程读取文件的带宽约为 3.5 Gbps。要突破此限制,需要采用多线程或多并发策略以充分利用存储与网络资源。
| threads | bw(GB/s) | bw/threads |
|---|---|---|
| 1 | 3.5 | 3.5 |
| 2 | 6.3 | 3.15 |
| 3 | 9.5 | 3.16 |
| 4 | 9.7 | 2.43 |
| 6 | 14.0 | 2.33 |
| 8 | 17.0 | 2.13 |
| 10 | 18.6 | 1.9 |
| 15 | 21 | 1.4 |
JuiceFS 连续读性能测试
在性能测试中,单线程连续读带宽约为 3.5 Gbps,随着线程数增加,整体吞吐量可逐渐接近网络带宽上限。为了方便评估自身环境的性能上限,JuiceFS 提供了 bj bench 子命令,可用于测试对象存储带宽。
在实际业务中,缓存往往比直接访问对象存储更常见。此时,可通过增大 buffer size 提高后台预读请求数,从而提升并发度并改善整体吞吐。例如,将 buffer size 调整至 400 MB(对应 100 个 4 MB 块的后台预读请求)后,并发度显著提升,整体吞吐量随之增强。
随机读性能
低并发随机读
在低并发且非异步访问场景下,每个请求需等待前一个完成后才能发出,因此延迟对整体性能的影响尤为显著。I/O 延迟可能来源于多方面,包括元数据查询延迟、对象存储访问延迟,以及本地缓存或分布式缓存读取延迟。在分析随机读性能时,需要重点关注这些延迟因素。
在 4 KB 随机冷读场景下,若 IOPS 仅为 8,且对象存储延迟约 125 毫秒,则可计算出系统并发度约为 1(8 IOPS × 125 ms ≈ 1000 ms)。
这表明当前处于近似单并发、请求串行阻塞的状态。在这种情况下,优化重点通常不在于进一步提升并发,而在于缩短访问路径、降低单次请求延迟,例如将数据预热至本地缓存。完成预热后,随机读路径可由对象存储切换至本地缓存,IOPS 可提升至约 12,000,接近本地磁盘的 I/O 水平。
更多推荐



所有评论(0)