<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>JuiceFS Blog</title><link>https://www.juicefs.com/zh-cn/blog/</link><description>Latest news from JuiceFS</description><atom:link href="http://juicefs.com/zh-cn/blog/latest/feed/" rel="self"/><language>zh-cn</language><lastBuildDate>Thu, 18 Jun 2026 07:28:58 +0000</lastBuildDate><item><title>JuiceFS PB 级数据同步优化：断点续传、安全与带宽控制</title><link>https://www.juicefs.com/zh-cn/blog/engineering/juicefs-sync-enhancements-checkpoint-encryption-ratelimit</link><description>&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;在数据迁移、跨云同步与对象存储备份等场景中，&lt;code&gt;juicefs sync&lt;/code&gt; 常用于执行大规模数据同步任务。当数据规模达到 TB 到 PB 级、对象数量达到数百万甚至数十亿级时，单次任务执行周期通常会延长到数小时甚至数天。&lt;/p&gt;
&lt;p&gt;在这个过程中，系统运行过程中通常会逐步暴露出以下几类问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;任务在网络抖动、进程异常退出或节点重启后，难以从一致状态继续执行，往往需要重新扫描或重复处理；  &lt;/li&gt;
&lt;li&gt;数据备份场景可能存在明文暴露风险并可能面临合规与安全要求；  &lt;/li&gt;
&lt;li&gt;多个同步任务并发运行时，带宽资源竞争明显，整体传输过程缺乏有效的全局控制手段。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;围绕这些场景，JuiceFS 1.4 在 &lt;code&gt;sync&lt;/code&gt; 中提供了三项能力增强：断点续传、数据加解密，以及全局流量控制。本文将围绕这三项能力，介绍其适用场景、实现机制和使用方式。&lt;/p&gt;
&lt;h2&gt;01 断点续传&lt;/h2&gt;
&lt;p&gt;在早期版本中，用户同步过程中遇到错误或者中断，重新执行任务时，&lt;code&gt;juicefs sync&lt;/code&gt; 需要重新扫描源端和目标端，再判断哪些对象已经完成、哪些对象仍需复制。对于上亿级对象或大量大文件场景，仅重新扫描本身就可能带来显著的时间成本和对象存储请求开销。&lt;/p&gt;
&lt;p&gt;为了解决这一问题，我们在 JuiceFS 1.4 中为 &lt;code&gt;sync&lt;/code&gt; 引入了 断点续传机制。启用后，&lt;code&gt;sync&lt;/code&gt; 会将任务进度保存到目标端。当任务中断后，用户只需重新执行相同命令，&lt;code&gt;sync&lt;/code&gt; 就会自动查找并加载与当前源端、目标端及关键参数匹配的 checkpoint，从上次未完成的位置继续执行，避免从头重新处理。&lt;/p&gt;
&lt;h3&gt;工作原理&lt;/h3&gt;
&lt;p&gt;启用 断点续传 后，&lt;code&gt;sync&lt;/code&gt; 会在目标端保存一个 JSON 格式的状态文件，文件名格式如下：&lt;/p&gt;
&lt;pre class="codehilite"&gt;&lt;code class="language-bash"&gt;.juicefs-sync-checkpoint.&amp;lt;hash&amp;gt;.json
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;其中，&lt;code&gt;&amp;lt;hash&amp;gt;&lt;/code&gt; 由源端、目标端和关键同步参数计算得到，用于确保当前任务只加载与自身匹配的 checkpoint，避免不同同步任务之间误用状态文件。&lt;/p&gt;
&lt;p&gt;断点续传的运行流程如下图所示：&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;Checkpoint 的流程&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;juicefs sync checkpoint 的保存、恢复与清理流程&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;sync&lt;/code&gt; 启动后，首先在目标端查找与当前任务匹配的 checkpoint。  &lt;/li&gt;
&lt;li&gt;如果找到匹配项，则从上次保存的状态恢复执行；如果未找到，则按正常流程扫描并开始同步。sync 会并发遍历多个前缀，每个前缀都有独立状态，包括是否已完成遍历、上次遍历到的位置、待同步对象以及同步失败的对象。  &lt;/li&gt;
&lt;li&gt;从 checkpoint 恢复时，sync 会先从每个前缀中记录的待同步对象和失败对象重新加入任务队列，对于上次尚未遍历完成的前缀，则从记录的位置继续扫描并同步；已经完成遍历的前缀只会继续处理 checkpoint 中尚未完成的对象。  &lt;/li&gt;
&lt;li&gt;任务运行过程中，&lt;code&gt;sync&lt;/code&gt; 会按设定间隔异步保存当前进度，默认每 10 秒保存一次。  &lt;/li&gt;
&lt;li&gt;任务正常完成后，checkpoint 文件会被自动删除；如果任务中断或失败，则会保留下来，供下次执行相同命令时继续恢复。&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;集群模式&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;集群模式架构示意图&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;在集群模式下，checkpoint 只有一份，由 Manager 统一维护。Worker 不直接读写目标端的 checkpoint 文件，而是负责从 Manager 拉取任务、执行同步并回传结果。Manager 会将 Worker 回传的完成对象、失败对象、统计信息和 multipart 状态合并到全局 checkpoint 中。&lt;/p&gt;
&lt;h3&gt;使用方式&lt;/h3&gt;
&lt;pre class="codehilite"&gt;&lt;code class="language-bash"&gt;# 启用断点续传
juicefs sync --enable-checkpoint SRC DST

# 自定义 checkpoint 保存间隔（默认 10s）
juicefs sync --enable-checkpoint --checkpoint-interval 30s SRC DST

# 忽略已有 checkpoint，强制从头同步
juicefs sync --enable-checkpoint --checkpoint-force-reset SRC DST
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;02 数据加解密&lt;/h2&gt;
&lt;p&gt;在跨云备份和归档场景中，客户端加密是常见的合规要求，例如数据主权、静态数据保护、敏感数据迁移等。此前，&lt;code&gt;juicefs sync&lt;/code&gt; 没有原生加解密能力，用户如果希望将数据加密后写在目的端，通常需要借助外部工具额外处理。&lt;/p&gt;
&lt;p&gt;在 JuiceFS 1.4 中，我们将流式加解密能力集成到 &lt;code&gt;sync&lt;/code&gt; 流程中，使用户可以在数据同步的同时完成加密、解密或重新加密，主要支持以下三类场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;加密写入&lt;/strong&gt;：将明文数据加密后写入目标端，适用于加密备份和归档场景。  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解密恢复&lt;/strong&gt;：从源端读取加密数据，解密后写入目标端，适用于数据恢复或明文迁移。  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;重新加密&lt;/strong&gt;：使用旧密钥解密源端数据，再使用新密钥加密后写入目标端，适用于密钥轮换或加密算法迁移。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;工作原理：分块流式加密&lt;/h3&gt;
&lt;p&gt;为了支持对象存储的 Range GET，并避免一次性加载大文件带来的高内存占用，&lt;code&gt;sync&lt;/code&gt; 采用固定 1 MiB 分块的流式加密方案。每个文件会先被拆分为多个明文块，再分别加密写入目标端。&lt;/p&gt;
&lt;p&gt;原始文件结构可以理解为：&lt;/p&gt;
&lt;pre class="codehilite"&gt;&lt;code class="language-bash"&gt;[chunk 1: 1 MiB][chunk 2: 1 MiB] ... [chunk N: ≤1 MiB]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;加密后，每个明文块会对应生成一个加密块。每个加密块由 4 字节头部和密文数据组成，其中 4 字节头部用于记录该块的实际密文长度，即 &lt;code&gt;ct_len&lt;/code&gt;：&lt;/p&gt;
&lt;p&gt;每个加密块： &lt;code&gt;[4B ct_len][ciphertext + padding]&lt;/code&gt; &lt;/p&gt;
&lt;p&gt;加密后的文件： [encrypted chunk 1][encrypted chunk 2] ... [encrypted chunk N]&lt;/p&gt;
&lt;p&gt;加密块的大小由明文块大小和加密开销共同决定，可以理解为 &lt;code&gt;plainChunkSize + overhead&lt;/code&gt;。其中，&lt;code&gt;plainChunkSize&lt;/code&gt; 固定为 1 MiB，&lt;code&gt;overhead&lt;/code&gt; 取决于所使用的加密算法和密钥类型。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;分块流式加密&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;juicefs sync 分块流式加密的基本结构与读写方式&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;这种设计的好处是，随机读取时只需要根据偏移定位到对应的加密块，并下载相关块数据，不必读取整个文件。相应地，加密后的对象会包含额外头部、填充和加密元数据，因此目标端对象通常会比原始明文文件更大。&lt;/p&gt;
&lt;h3&gt;支持的算法&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: left;"&gt;参数值&lt;/th&gt;
&lt;th style="text-align: left;"&gt;对称算法&lt;/th&gt;
&lt;th style="text-align: left;"&gt;密钥封装&lt;/th&gt;
&lt;th style="text-align: left;"&gt;适用场景&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;aes256gcm-rsa（默认）&lt;/td&gt;
&lt;td style="text-align: left;"&gt;AES-256-GCM&lt;/td&gt;
&lt;td style="text-align: left;"&gt;RSA&lt;/td&gt;
&lt;td style="text-align: left;"&gt;通用场景&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;chacha20-rsa&lt;/td&gt;
&lt;td style="text-align: left;"&gt;ChaCha20-Poly1305&lt;/td&gt;
&lt;td style="text-align: left;"&gt;RSA&lt;/td&gt;
&lt;td style="text-align: left;"&gt;对 AES 硬件加速支持有限的环境&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;sm4gcm&lt;/td&gt;
&lt;td style="text-align: left;"&gt;SM4-GCM&lt;/td&gt;
&lt;td style="text-align: left;"&gt;SM2&lt;/td&gt;
&lt;td style="text-align: left;"&gt;需要国密算法的场景&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;使用方式&lt;/h3&gt;
&lt;p&gt;下面以 RSA 密钥为例说明加密、解密和重新加密的使用方式。&lt;/p&gt;
&lt;p&gt;生成密钥对：&lt;/p&gt;
&lt;pre class="codehilite"&gt;&lt;code class="language-bash"&gt;# 生成 RSA 私钥（公钥内嵌其中，JuiceFS 自动提取）
openssl genrsa -out private.pem 2048

# 带密码保护的私钥
openssl genrsa -aes256 -out private.pem 2048
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;场景一：加密写入目标端&lt;/p&gt;
&lt;pre class="codehilite"&gt;&lt;code class="language-bash"&gt;juicefs sync /local/data s3://mybucket/backup 
    --encrypt-rsa-key /path/to/private.pem
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;场景二：解密读取源端，用于数据恢复或明文迁移。&lt;/p&gt;
&lt;pre class="codehilite"&gt;&lt;code class="language-bash"&gt;juicefs sync s3://mybucket/backup /local/data 
    --decrypt-rsa-key /path/to/private.pem
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;场景三：重新加密，用于密钥轮换或算法迁移。&lt;/p&gt;
&lt;pre class="codehilite"&gt;&lt;code class="language-bash"&gt;# 解密旧密钥加密的数据，用新密钥重新加密写入新存储
juicefs sync s3://old-bucket/encrypted s3://new-bucket/re-encrypted 
    --decrypt-rsa-key /path/to/old-private.pem 
    --encrypt-rsa-key /path/to/new-private.pem
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;如果私钥设置了密码，可以通过环境变量传入。&lt;/p&gt;
&lt;pre class="codehilite"&gt;&lt;code class="language-bash"&gt;# 加密场景使用 JFS_ENCRYPT_RSA_PASSPHRASE
export JFS_ENCRYPT_RSA_PASSPHRASE=&amp;quot;your-passphrase&amp;quot;
juicefs sync /local/data s3://mybucket/backup --encrypt-rsa-key private.pem

# 解密场景使用 JFS_DECRYPT_RSA_PASSPHRASE
export JFS_DECRYPT_RSA_PASSPHRASE=&amp;quot;your-passphrase&amp;quot;
juicefs sync s3://mybucket/backup /local/data --decrypt-rsa-key private.pem
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;注意&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;加密后的数据采用 JuiceFS 私有格式存储，需通过 &lt;code&gt;juicefs sync&lt;/code&gt; 并提供对应密钥进行解密读取。  &lt;/li&gt;
&lt;li&gt;请妥善备份加解密所用私钥；私钥一旦丢失，已加密数据将无法解密访问。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;03 全局流量控制&lt;/h2&gt;
&lt;p&gt;在早期版本中，&lt;code&gt;juicefs sync&lt;/code&gt; 已经支持通过 &lt;code&gt;--bwlimit&lt;/code&gt; 对单个 &lt;code&gt;sync&lt;/code&gt; 进程限速。但在多个 &lt;code&gt;sync&lt;/code&gt; 进程同时运行时，例如分布式同步中的多个 Worker，或多个独立同步任务共享同一条出口链路，单进程限速并不能约束整体带宽使用量，仍然可能导致出口带宽被打满，影响其他业务流量。&lt;/p&gt;
&lt;p&gt;我们在 JuiceFS 1.4 中新增了 &lt;code&gt;--traffic-control-url&lt;/code&gt; 参数。用户可以将多个 &lt;code&gt;sync&lt;/code&gt; 进程接入同一个外部流量控制服务，由该服务统一分配带宽配额，从而实现跨进程、跨任务的全局限速。&lt;/p&gt;
&lt;h3&gt;工作原理&lt;/h3&gt;
&lt;p&gt;全局流量控制采用令牌桶模型。多个 &lt;code&gt;sync&lt;/code&gt; 进程在传输数据前，都会向同一个流量控制服务申请字节配额：&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;全局流量&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;juicefs sync 全局流量控制实现流程&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;每个 &lt;code&gt;sync&lt;/code&gt; 进程在传输数据前，会向控制服务申请一定数量的字节配额（credit）。控制服务根据当前总带宽使用情况，决定本次授予多少配额，以及配额的有效时间。配额用完后，&lt;code&gt;sync&lt;/code&gt; 会继续申请新的配额；如果配额即将过期但尚未用完，未使用的部分会提前归还给控制服务。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;控制服务通过 HTTP 接口提供配额申请和归还能力，接口需由用户自行实现或接入现有服务：&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="codehilite"&gt;&lt;code class="language-bash"&gt;POST /traffic-control
Content-Type: application/json

请求：
{&amp;quot;bytes&amp;quot;: 1048576}
  bytes &amp;gt; 0: 申请 bytes 字节的额度
  bytes &amp;lt; 0: 归还 |bytes| 字节的未使用额度

响应：
{&amp;quot;granted&amp;quot;: 524288, &amp;quot;expired&amp;quot;: 1000}
  granted: 本次授予的字节数
  expired: 额度有效期（毫秒）
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;在同步过程中，&lt;code&gt;sync&lt;/code&gt; 会在传输数据前向流量控制服务申请配额。如果当前没有可用配额，传输会阻塞等待，直到获得新的配额。通过这种方式，多个同步任务可以共享同一个全局带宽上限，避免并发任务各自限速但总流量失控的问题。&lt;/p&gt;
&lt;h3&gt;使用方式&lt;/h3&gt;
&lt;pre class="codehilite"&gt;&lt;code class="language-bash"&gt;# 先部署流量控制服务（示例：监听 8080 端口，限制总带宽 100 Mbps）
# （服务实现由用户自行决定，juicefs 只负责调用接口）

# 多个 sync 进程接入同一个控制服务
juicefs sync SRC1 DST1 --traffic-control-url http://127.0.0.1:8080/traffic-control &amp;amp;
juicefs sync SRC2 DST2 --traffic-control-url http://127.0.0.1:8080/traffic-control &amp;amp;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;--traffic-control-url 可与 --bwlimit 同时使用，两个限制独立生效：&lt;code&gt;--bwlimit&lt;/code&gt; 用于限制单个 &lt;code&gt;sync&lt;/code&gt; 进程的最大带宽，&lt;code&gt;--traffic-control-url&lt;/code&gt; 用于控制多个 &lt;code&gt;sync&lt;/code&gt; 进程的全局带宽。&lt;/p&gt;
&lt;pre class="codehilite"&gt;&lt;code class="language-bash"&gt;# 单进程不超过 50 Mbps，同时所有进程合计不超过服务端配置的上限
juicefs sync SRC DST 
    --bwlimit 50 
    --traffic-control-url http://controller:8080/traffic-control
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;04 小结&lt;/h2&gt;
&lt;p&gt;JuiceFS 1.4 对 &lt;code&gt;sync&lt;/code&gt; 的增强包括：断点续传降低了任务中断后的恢复成本，数据加解密提高了数据备份的安全性，全局流量控制则帮助多个同步任务更有序地共享带宽。对于数据迁移、跨云同步、对象存储备份和加密归档等场景，用户可以根据任务规模、网络环境和安全要求，灵活组合使用这些能力。&lt;/p&gt;&lt;/div&gt;</description><pubDate>Thu, 18 Jun 2026 07:28:58 +0000</pubDate><guid>https://www.juicefs.com/zh-cn/blog/engineering/juicefs-sync-enhancements-checkpoint-encryption-ratelimit</guid></item><item><title>星辰征途 42 倍小文件性能提升、85% 吞吐增长：多云 AI 场景下的 JuiceFS 存储实践</title><link>https://www.juicefs.com/zh-cn/blog/user-stories/juicefs-multi-cloud-ai-massive-throughput-growth</link><description>&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;星辰征途是一家聚焦 AI 搜索与电商场景多模态 AIGC 应用的初创公司，成立两年多，业务主要面向海外市场。公司目前的主要产品包括：Gensmo（gensmo.com） 聚焦时尚穿搭，提供虚拟试穿、造型推荐和商品搜索；ZooClaw（zooclaw.ai） 面向更广泛的生活与工作场景，提供 AI Agent 服务。&lt;/p&gt;
&lt;p&gt;本文将介绍星辰征途业务背后的存储实践，分享我们在统一存储选型、架构设计和性能调优中的思考与经验。目前，JuiceFS 已在生产环境使用一年多，管理文件数超过 1 亿，业务横跨 Oracle、DigitalOcean 和 GCP 三朵云，并成为支撑模型训练、推理、数据处理和在线 Agent 的统一存储层。&lt;/p&gt;
&lt;h2&gt;01 统一存储需求与建设思路&lt;/h2&gt;
&lt;h3&gt;四类场景，四种 I/O 诉求&lt;/h3&gt;
&lt;p&gt;到目前为止，星辰征途在存储上主要涉及四类场景，支撑 Gensmo 和 ZooClaw 的业务。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;业务类型&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;星辰征途业务类型&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;&lt;strong&gt;第一类：模型训练&lt;/strong&gt;&lt;br&gt;
公司自研模型包括 Gensmo 的 try-on 模型和视频生成模型，用于向 C 端和 B 端客户展示穿搭效果、360° 模型动作或特效场景。模型训练涉及大文件的顺序写入和 checkpoint 保存，对存储系统要求：高容量、高性能顺序 I/O。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第二类：模型推理服务&lt;/strong&gt;&lt;br&gt;
推理服务对 I/O 的核心需求是高并发顺序读，数据加载到本地缓存以提高命中率。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第三类：数据处理&lt;/strong&gt;&lt;br&gt;
我们会抓取海外独立电商站的商品、服饰、评价等数据，用于训练模型和业务运营分析。该场景面临大量小文件（单张图片几百 KB），对存储系统的高 IOPS 并发能力是挑战。&lt;/p&gt;
&lt;p&gt;工程优化方面，我们使用 Ray Data 并行处理，将海量小文件聚合成 Parquet 大文件（几十 GB 到上百 GB），形成可复用的数据基础层，后续 embedding、检索、推荐等任务重复使用，大幅降低对文件系统的压力，同时兼顾训练和推理场景的需求。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第四类：在线 Agent&lt;/strong&gt;&lt;br&gt;
在线 Agent 场景与前面主要的离线场景不同，虽然存在大量小文件，但这些文件是在线服务生成，且每个 Agent 的数据只读写自身，不涉及跨 Agent 分布式处理。存储系统需支撑高并发访问和快速响应，但不要求跨 Agent 数据协调。&lt;/p&gt;
&lt;p&gt;综合来看，这四类场景对存储系统提出了两类要求：离线训练、推理和数据处理需要高吞吐、高并发和缓存能力；在线 Agent 则更关注低延迟、数据隔离和稳定性。在明确这些业务需求之后，一个自然的问题是：是否需要考虑多云架构？从平台建设之初，我们的答案就是肯定的。&lt;/p&gt;
&lt;h3&gt;云中立不是理念，是议价能力&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;云中立的目的不是追求技术本身，而是满足基础设施团队的核心需求：保持算力和资源的可漂移性以及与不同云供应商的议价能力。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;对于海外业务，如果计算和存储长期绑定在单一云供应商，随着业务增长或价格变化，灵活调整算力就会受限。尤其在 AI 场景中，GPU 资源价格和供应波动很大：当前便宜的资源，过一段时间可能价格上升或供应不足；业务增长后需要的计算规模，也可能原云供应商无法满足。&lt;/p&gt;
&lt;p&gt;因此，我们希望存储层与具体云厂商解耦，使数据保持云中立。这样，训练、推理或在线 Agent 工作负载可以漂移到更符合成本和性能要求的云上，而不需要反复复制或重新配置数据。&lt;/p&gt;
&lt;h3&gt;POSIX：统一存储体验的基础&lt;/h3&gt;
&lt;p&gt;另一个在平台建设需要考虑的核心问题就是：如何让研发团队在多云、多对象存储环境下获得一致的操作体验。&lt;/p&gt;
&lt;p&gt;对于单一业务场景来说，直接使用对象存储已经足够。但当训练、推理、数据处理和在线 Agent 共用同一套数据体系时，不同对象存储接口带来的开发和运维成本会被不断放大。因此，我们希望在底层存储之上提供统一抽象，&lt;strong&gt;而 POSIX 文件系统语义正是最适合承载这种抽象的方式。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;通过 JuiceFS，我们将底层对象存储（无论是 GCS、S3 还是 R2）统一映射为 POSIX 文件系统，并挂载为本地路径。这样一来，从本地开发到生产环境，研发团队面对的始终是同一套文件系统接口和访问路径，而无需关心底层数据究竟存储在哪朵云、使用哪种对象存储。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;简单来说，理想的云存储体验，是让工程师无需感知底层多云环境的存在，他们看到的永远是一条本地路径的数据。&lt;/strong&gt;这也是我们后续选择 JuiceFS 的重要原因之一。&lt;/p&gt;
&lt;h2&gt;02 选型：从 GCS Fuse、S3 Fuse 到 JuiceFS&lt;/h2&gt;
&lt;p&gt;由于离线和在线场景的需求差异明显，存储选型也呈现出两条不同路径。&lt;/p&gt;
&lt;h3&gt;离线：调研业界主流方案后，一开始就选了 JuiceFS&lt;/h3&gt;
&lt;p&gt;在离线场景中，我们面对的是多云环境和高吞吐需求。因此，在系统搭建之前，团队对业界主流方案进行了调研，并根据核心诉求逐一对比：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;自建并行文件系统：性能最强，但成本高、绑定硬件且跨云能力有限；  &lt;/li&gt;
&lt;li&gt;云托管并行文件系统：省心，但锁定单一云厂商，成本仍高；  &lt;/li&gt;
&lt;li&gt;裸 FUSE：成本低，但 POSIX 语义和性能都不足；  &lt;/li&gt;
&lt;li&gt;缓存编排层：需要额外叠加底层存储，运维复杂。&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;方案&lt;/th&gt;
&lt;th&gt;云中立&lt;/th&gt;
&lt;th&gt;POSIX 语义&lt;/th&gt;
&lt;th&gt;高吞吐&lt;/th&gt;
&lt;th&gt;分布式缓存&lt;/th&gt;
&lt;th&gt;成本 / 运维&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;自建并行文件系统（如 Lustre）&lt;/td&gt;
&lt;td&gt;❌ 绑定硬件&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅✅&lt;/td&gt;
&lt;td&gt;部分&lt;/td&gt;
&lt;td&gt;成本高，运维重&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;云托管并行文件系统（如 Filestore）&lt;/td&gt;
&lt;td&gt;❌ 锁定单云&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;成本高，运维较轻&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;对象存储 + FUSE（S3FS / GCS Fuse）&lt;/td&gt;
&lt;td&gt;⚠️ 锁云&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;成本低，运维轻&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;缓存编排层（Alluxio / Fluid）&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;需叠加底层存储，运维重&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JuiceFS&lt;/td&gt;
&lt;td&gt;✅ 后端任选&lt;/td&gt;
&lt;td&gt;✅ 完整&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅ 内建&lt;/td&gt;
&lt;td&gt;对象存储成本，CSI 接入&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;相比之下，JuiceFS 同时满足了我们对&lt;strong&gt;云中立、完整 POSIX、内建分布式缓存和对象存储后端&lt;/strong&gt; 的核心要求，而其他方案基本都会缺少其中一环。因此，在离线场景下，我们没有太多犹豫，一开始就选定了 JuiceFS。&lt;/p&gt;
&lt;h3&gt;Agent：从 GCS Fuse 踩坑，迁到 JuiceFS&lt;/h3&gt;
&lt;p&gt;早期业务主要部署在 Google 云上，使用 Google Cloud Storage（GCS）通过 GCS Fuse 挂载到 GKE Pod。实践中发现，这种方案无法满足在线 Agent 对稳定性、性能和云中立的要求。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;最主要的问题是 SIGKILL 场景下的数据丢失&lt;/strong&gt;。GCS Fuse 采用异步 write-back 机制，应用进程的 &lt;code&gt;write&lt;/code&gt; 返回成功后，数据可能仍停留在本地缓冲区，并未真正写入 GCS。一旦 Pod 被 OOM kill 或 SIGKILL，已经“看起来写成功”的数据可能永久丢失，在 Agent 场景中会直接表现为会话数据丢失。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第二类问题是小文件性能和 POSIX 语义不足&lt;/strong&gt;。Agent 工作目录中通常包含多个小文件，并存在频繁追加写入。GCS Fuse 在 &lt;code&gt;open&lt;/code&gt;、&lt;code&gt;stat&lt;/code&gt; 等操作上延迟较高，同时对 &lt;code&gt;rename&lt;/code&gt;、&lt;code&gt;flock&lt;/code&gt;、&lt;code&gt;symlink&lt;/code&gt; 等 POSIX 语义支持不完整，难以满足在线服务的稳定运行要求。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第三类问题是云锁定和高并发稳定性&lt;/strong&gt;。GCS Fuse 基本绑定在 GCP 生态内使用，不符合我们对云中立的要求；在高并发 Agent 场景下，稳定性也存在不足。&lt;/p&gt;
&lt;p&gt;基于这些问题，我们尝试将在线 Agent 场景迁移到 JuiceFS。&lt;/p&gt;
&lt;p&gt;JuiceFS 能解决数据丢失问题，关键在于它的写路径和独立元数据引擎。JuiceFS 将数据和元数据分离：数据 chunk 先上传到对象存储，元数据再原子提交到独立元数据引擎，这之后才算写成功。也就是说，写成功真正意味着数据已经落地，SIGKILL 不会丢失已确认的数据。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;更本质地说，GCS Fuse 是以文件系统形式暴露对象存储，而 JuiceFS 是基于对象存储构建真正的文件系统。正是这层独立元数据引擎，加上完整 POSIX 支持、云中立、内建分布式缓存和生态工具链，使 JuiceFS 更符合在线 Agent 对可靠性、一致性和高并发访问的要求&lt;/strong&gt;。目前，在线 Agent 已在生产环境稳定运行，JuiceFS 也成为公司多场景下的统一存储方案。&lt;/p&gt;
&lt;h2&gt;03 新架构：JuiceFS 在多云的部署&lt;/h2&gt;
&lt;h3&gt;离线：多云算力漂移，统一元数据 + R2&lt;/h3&gt;
&lt;p&gt;针对离线场景云中立、算力漂移和高吞吐的需求，我们设计了如下架构：&lt;/p&gt;
&lt;p&gt;底层对象存储选择 Cloudflare R2 作为后端。R2 不绑定任何云厂商，且对出站流量免费，非常适合跨云的高吞吐训练场景。相比之下，其他对象存储如 GCS 或 AWS S3 虽然存储成本低，但出站流量费用可能极高，会显著增加离线训练成本。例如，GCS 一个月 1TB 的存储费用约 20 美元，但出站流量可能高达 20–140 美元。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;架构&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;离线场景存储架构&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;在 R2 之上，我们部署了 JuiceFS 企业版，实现多云的统一文件系统。无论算力在 Oracle 还是 DigitalOcean，训练、推理或数据处理任务都使用同一套路径，工程师无需感知底层云变化。&lt;/p&gt;
&lt;p&gt;算力层包括 Oracle 上的 H100 GPU 和 DigitalOcean 上的 H200 GPU，运行 Slurm 和 KubeRay 的训练与推理统一方案。每个 GPU 节点的本地 NVMe 构建分布式缓存，形成跨节点共享缓存池。数据集首次访问时从 R2 回源，后续基本命中缓存，以吸收跨云访问带来的延迟。&lt;/p&gt;
&lt;p&gt;基础设施管理通过 Terraform 完成 IaaC 编排，所有网络、存储、训练任务、Ray 集群和推理引擎均可一键部署。只要云厂商支持 Kubernetes，计算资源和任务都可以无缝拉起，实现跨云快速扩展和资源调整。&lt;/p&gt;
&lt;h3&gt;在线：低延迟优先与云内独立元数据&lt;/h3&gt;
&lt;p&gt;在线 Agent 场景以 ZooClaw 为例，核心诉求是为大量 Agent 提供统一存储底座，并实现统一管理、目录隔离和计费，更关注低延迟、小文件写入和高并发访问。如果存储链路跨云，I/O 延迟会明显上升，不适合在线服务。因此，我们尽量让对象存储、元数据服务和业务 Pod 都部署在同一朵云内。&lt;/p&gt;
&lt;p&gt;目前这套在线架构部署在 GCP 上，底层对象存储使用本云的 Google Cloud Storage（GCS），元数据层则在 GCP 私有 VPC 内部署独立的三节点 Raft 集群。这样可以让对象存储、元数据服务和业务 Pod 都留在同一云内，降低访问延迟，并提高小文件写密集场景下的 IOPS 表现。&lt;/p&gt;
&lt;p&gt;在 Kubernetes 层面，我们通过 JuiceFS CSI 挂载同一个 RWX PVC，不同 bot Pod 使用各自的 subPath 访问独立目录，并通过 token 按环境限制访问范围，实现文件系统级的数据隔离。对于每个 Agent 来说，它看到的是自己的本地工作目录；对于平台侧来说，底层仍然是一套统一的存储系统，便于统一管理和计费。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;流程&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;在线场景存储架构&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;如果未来 GCP 的资源或成本不再合适，这套架构仍然具备漂移能力。我们基于 Terraform 和 Kubernetes 进行编排，可以在另一朵云上拉起同样的计算和存储结构，再将对应的元数据与数据同步过去。在线 Agent 业务天然可以按 bot、用户或租户分批切换，因此不需要一次性整体迁移。&lt;/p&gt;
&lt;p&gt;回顾离线与在线两个场景，二者的目标不同：离线关注跨云共享、算力漂移和高吞吐，在线 Agent 则关注低延迟、高并发，同时保留按需漂移能力。因此，我们没有为所有场景套用同一种后端方案，而是在 JuiceFS 之上按场景做差异化设计。这样既保留了统一的数据管理和工程使用体验，也让每个场景都能选择更合适的元数据和对象存储部署方式。&lt;/p&gt;
&lt;h2&gt;04 调优实践：分布式缓存 / writeback / S3 Gateway&lt;/h2&gt;
&lt;p&gt;在统一架构落地后，我们仍需根据不同业务场景进行针对性的性能优化和访问策略调整。&lt;/p&gt;
&lt;h3&gt;同一个缓存，两套优化策略&lt;/h3&gt;
&lt;p&gt;分布式缓存是 JuiceFS 中非常关键的能力，直接影响 IOPS、吞吐和访问延迟。在离线和在线两个场景中，缓存的目标与实现方式存在显著差异。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;在离线场景中，核心目标是支撑大规模训练和数据处理的高吞吐，同时保障跨云共享和算力漂移。&lt;/strong&gt;为此，我们尽量将 R2 中的数据缓存到本地。训练、推理和数据处理运行在配备 NVMe SSD 的 H100、H200 GPU 节点上，单节点约 50T，十几台节点可形成几百 T 的分布式缓存空间。首次访问数据需要从 R2 回源，速度相对较慢，但首读完成后，训练、数据处理和推理任务基本能命中缓存，I/O 性能接近本地访问。在离线场景中，因写入的是大规模 checkpoint 或模型权重文件（单个文件可达数百 GB 至数 TB），数据安全要求极高，因此通常不启用 writeback，以确保写入绝对安全。&lt;/p&gt;
&lt;p&gt;在线 Agent 场景的核心目标是低延迟、高并发的小文件访问，同时保证每个 Agent 的数据隔离。缓存主要用于提升小文件写入和访问性能，每个 Agent Pod 挂载同一个支持 RWX 的 PVC，并通过 subPath 隔离目录，缓存失效时间设置为 3,600 秒，覆盖高频访问场景。由于每个 Agent 通常只访问自己的目录，这种缓存策略不要求严格跨 Agent 数据一致性，数据仅在必要的离线分析或运营排查中与对象存储保持最终一致。&lt;/p&gt;
&lt;p&gt;在线场景中，为了进一步提升小文件写入和高并发性能，缓存策略可以配合 writeback 使用。&lt;strong&gt;Writeback 的核心目标是以可控的数据安全风险换取更高的写入吞吐&lt;/strong&gt;。这意味着，在单个节点上运行的多个 Agent，如果某个 Agent 在写入过程中出现异常，仅会影响该 Agent 的单次产物，如 PPT、图片或临时文档，这些数据可以重新生成。借助 writeback，在线 Agent 在高并发、小文件写入时能够获得明显的性能提升，同时仍保持系统整体的稳定性和数据隔离。&lt;/p&gt;
&lt;h3&gt;一份数据，多种接口&lt;/h3&gt;
&lt;p&gt;S3 Gateway 在我们的架构中承担数据分发层角色，将 JuiceFS 中的数据以标准 S3 接口对外提供服务。在 Agent 场景下，无论是配置文件，还是生成的 PPT、图片或视频，数据最终都存放在同一套 JuiceFS 文件系统中。然而，这些数据往往需要以 URL 的形式分享给外部用户，POSIX 挂载方式显然不适用。&lt;/p&gt;
&lt;p&gt;因此，我们通过 JuiceFS S3 Gateway 将同一份数据直接暴露为标准 S3 接口。内部服务继续使用 POSIX 接口，而外部系统通过 S3 或 HTTP 协议访问同一份数据，无需额外复制。为了提升安全性和访问性能，我们在 S3 Gateway 前增加了 Cloudflare Worker 和 CDN：用户请求先通过 Worker 完成路径校验和访问控制，再转发到 Gateway 获取数据，同时通过 CDN 边缘缓存和 ETag 校验减少回源请求。&lt;/p&gt;
&lt;p&gt;这种设计带来了两个核心收益：第一，多层访问隔离保证数据安全，包括 JuiceFS 目录隔离、S3 Gateway 权限控制以及 Worker 层的代码级校验；第二，通过 CDN 缓存减少跨区域访问的延迟，提高大文件（如视频或图片）的访问性能。对于全球用户而言，这意味着即使数据存储在 GCP 美东区域，用户也可以从最近的边缘节点高效访问内容。&lt;/p&gt;
&lt;p&gt;从整体架构来看，内部训练、推理和 Agent 服务使用 POSIX 文件系统，而对外分发则通过 S3 Gateway 提供标准接口。&lt;strong&gt;同一份数据支持多种访问方式，无需额外复制&lt;/strong&gt;。&lt;/p&gt;
&lt;h2&gt;05 性能调优结果&lt;/h2&gt;
&lt;h3&gt;离线场景：顺序写吞吐提升 ~4×，缓存命中读 7–8 GB/s&lt;/h3&gt;
&lt;p&gt;在离线场景下，我们对顺序读写进行了性能基准测试。图表中展示了优化前后的对比：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;顺序写：单进程写入模型产出或 checkpoint 时约 700 MB/s，利用多进程、多节点并行写入可超过 1 GB/s，足以支撑大规模训练场景下的顺序写入需求。  &lt;/li&gt;
&lt;li&gt;顺序读：数据处理阶段，将小文件聚合成大文件并加载到分布式缓存后，顺序读命中缓存可达到 6.7–7.8 GB/s，接近本地 NVMe 性能。模型推理任务也可直接从本地缓存加载 checkpoint，无需跨节点拷贝。&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: left;"&gt;测试项（JuiceFS on R2，离线）&lt;/th&gt;
&lt;th style="text-align: left;"&gt;无优化基线&lt;/th&gt;
&lt;th style="text-align: left;"&gt;优化后（分布式缓存 + 调参）&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;顺序写：大块&lt;/td&gt;
&lt;td style="text-align: left;"&gt;~231 MB/s&lt;/td&gt;
&lt;td style="text-align: left;"&gt;~714 MB/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;顺序写：大批量 20–50 GB&lt;/td&gt;
&lt;td style="text-align: left;"&gt;~256–265 MB/s&lt;/td&gt;
&lt;td style="text-align: left;"&gt;840 MB/s ~ 1.1 GB/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;顺序读：分布式缓存命中&lt;/td&gt;
&lt;td style="text-align: left;"&gt;-&lt;/td&gt;
&lt;td style="text-align: left;"&gt;6.7 ~ 7.8 GB/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;顺序读：冷读回源 R2&lt;/td&gt;
&lt;td style="text-align: left;"&gt;-&lt;/td&gt;
&lt;td style="text-align: left;"&gt;~427 MB/s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;分布式缓存还带来了工程效率上的收益。训练、推理和数据处理可以共享同一套文件路径，减少了 checkpoint 在不同节点或服务之间复制的需求。新产出的模型权重可直接被推理服务加载，降低了数据流转成本，也提升了训练到部署的衔接效率。&lt;/p&gt;
&lt;h3&gt;在线场景：小文件写入性能提升 ~42×，大文件吞吐提升 ~85%&lt;/h3&gt;
&lt;p&gt;最初方案中，元数据服务部署在 OCI，后端对象存储使用 R2，在线业务在 GCP 访问时需要跨公网，请求链路中的元数据 RTT（Round-Trip Time） 约为 12.7 ms，小文件吞吐只有约 24 files/s；同时，R2 偶发 30 s PUT 超时，甚至会影响 bot 的稳定性。&lt;/p&gt;
&lt;p&gt;优化措施包括：一是开启 writeback 并调整缓存 TTL，大文件写入吞吐提升约 85%；二是将元数据和对象存储迁移到 GCP 内网，元数据在私有 VPC 三节点 Raft 集群，对象存储改为 GCS 并结合 NVMe 缓存。优化后，元数据 RTT 降至约 5.8 ms，小文件吞吐提升至约 1000 files/s，整体性能约提升 42 倍。&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;06 小结&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;经过一年多实践，JuiceFS 已成为星辰征途基础设施中的核心存储层。它不仅支撑超过 1 亿文件、横跨三朵云和多类业务场景的稳定运行，更重要的是统一了训练、推理、数据处理和在线 Agent 的存储体系。&lt;/p&gt;
&lt;p&gt;对于一家海外初创公司而言，灵活且运维简便的基础设施至关重要，这有助于团队将精力集中在业务创新上。统一存储体系为上层业务和研发提供一致接口，而底层资源可以根据场景灵活调度：离线场景围绕算力成本实现动态漂移，在线场景优先保证低延迟和高并发，同时保留按需迁移能力。这样的设计既保持了上层体验的一致性，又使算力成本可议价、资源可漂移，为未来扩展到更多云和区域奠定了基础。&lt;/p&gt;&lt;/div&gt;</description><pubDate>Fri, 12 Jun 2026 03:17:51 +0000</pubDate><guid>https://www.juicefs.com/zh-cn/blog/user-stories/juicefs-multi-cloud-ai-massive-throughput-growth</guid></item><item><title>JuiceFS 1.4｜大规模元数据操作优化：批量删除、克隆与 Redis 缓存全解析</title><link>https://www.juicefs.com/zh-cn/blog/engineering/juicefs-massive-metadata-optimization</link><description>&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;在 AI 训练、数据集管理等大规模文件访问场景中，随着文件数量和访问并发增加，元数据层往往更早成为性能瓶颈。无论是删除百万级小文件、克隆大规模数据集，还是高并发目录遍历，元数据引擎的响应能力都会直接影响上层业务效率。&lt;/p&gt;
&lt;p&gt;JuiceFS 社区版 1.4 在元数据引擎层面引入了三项优化：批量删除（Batch Unlink）、批量克隆（Batch Clone）和 Redis 客户端缓存（Client-Side Caching），分别面向大规模删除、元数据克隆和热点元数据读取场景，减少事务提交、网络交互和重复查询开销。在 100,000 个文件的 flat 目录测试中，批量删除最高提升 93 倍，批量克隆最高提升 24 倍。本文将从问题背景、设计思路和性能收益三个方面介绍这些优化。&lt;/p&gt;
&lt;h2&gt;01 删除：从逐个回收到批量事务&lt;/h2&gt;
&lt;p&gt;在 JuiceFS 的元数据与数据分离架构下，删除文件不仅移除目录项，还需要更新 inode 引用计数、回收空间和 inode、处理回收站、调整配额等多项元数据操作，这些操作通常必须在同一个事务中完成。&lt;/p&gt;
&lt;p&gt;当目录中包含数十万甚至数百万个文件时，早期 &lt;code&gt;rm -rf&lt;/code&gt; 的逐文件删除方式会迅速暴露性能瓶颈：每个 &lt;code&gt;unlink&lt;/code&gt; 请求都需要经过 FUSE 协议在内核态与用户态之间交互，并触发一次独立的元数据事务提交。文件数量越多，系统调用、上下文切换、网络往返和事务提交开销累积越明显。&lt;/p&gt;
&lt;p&gt;JuiceFS 此前已引入 &lt;code&gt;juicefs rmr&lt;/code&gt; 命令来缓解这一问题。rmr 绕过 FUSE 协议层，通过控制文件直接将删除请求投递到客户端内部，同时支持多线程并发删除（默认 50 线程），相比 &lt;code&gt;rm -rf&lt;/code&gt; 有显著提升。但 rmr 的每次删除仍然是独立的事务——十万个文件就需要十万次事务。&lt;strong&gt;本次的批量删除优化，正是要在 rmr 的基础上，将同一目录下的多次独立事务合并为一次批量事务，进一步消除网络开销。&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;核心优化思路&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;解决这个问题的关键在于将"多次小事务"合并为"少量大事务"。JuiceFS 在元数据引擎层面新增了 BatchUnlink 接口，它允许客户端将同一目录下的多个非目录文件在一次调用中批量删除。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在递归清空目录时，JuiceFS 会同时从两个层面减少删除开销：一方面，不同子目录之间可以并发处理，充分利用多线程删除能力；另一方面，在同一目录内部，会将普通文件和符号链接等非目录条目按批次提交给 &lt;code&gt;BatchUnlink&lt;/code&gt; 处理。这样，原本需要逐个发起的 &lt;code&gt;unlink&lt;/code&gt; 操作，就可以在元数据层面合并为更少的批量事务。&lt;/p&gt;
&lt;p&gt;需要注意的是，&lt;code&gt;BatchUnlink&lt;/code&gt; 并不直接批量删除目录。目录删除遵循递归顺序：先清空子目录中的内容，再删除子目录本身。因此， BatchUnlink 的作用范围限定在同一目录下的普通文件和符号链接上。&lt;strong&gt;这个限制既保证了递归删除语义的正确性，也避免了批量操作影响目录树结构的一致性。&lt;/strong&gt;&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;JuiceFS 删除操作优化路径&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;JuiceFS 删除操作优化路径&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;h3&gt;各引擎的实现策略&lt;/h3&gt;
&lt;p&gt;在 &lt;code&gt;BatchUnlink&lt;/code&gt; 的实现中，JuiceFS 针对不同元数据后端采用了相应的批量化策略，以减少事务提交次数和网络往返。&lt;/p&gt;
&lt;p&gt;在 SQL 后端（MySQL、PostgreSQL 等），原来的逐条删除意味着每次都要执行独立的 INSERT、DELETE、UPDATE 语句序列。&lt;strong&gt;引入 BatchUnlink 后，系统会先通过一次批量查询获取所有待删除条目的 edge 记录，再通过一次带行锁的批量查询获取所有涉及的 inode 属性。&lt;/strong&gt;随后，在同一个事务内批量执行 edge 删除、inode 状态更新（nlink 递减或标记为待清理）、delfile 条目插入等操作。原来 N 个文件的删除需要 N 次独立事务，现在只需要一次。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;在 Redis 后端，优化策略则利用了 Redis 的 Pipeline 和事务机制。&lt;/strong&gt;原来的逐条删除每次都需要独立的命令交互，而 BatchUnlink 将多个文件的 HDEL（删除 dentry）、ZADD（加入待清理队列）、SET（更新 inode 属性）、INCRBY（更新统计计数）等命令全部放入一个 Pipeline 中，在单次 MULTI/EXEC 事务中原子执行。为了控制单次事务中的命令总量，避免阻塞 Redis 单线程过久，批次大小固定为 250 个条目。&lt;/p&gt;
&lt;p&gt;在 TiKV 后端，BatchUnlink 同样将多次删除操作合并到单次事务中，利用 TiKV 的批量写入能力减少网络往返和事务开销。&lt;strong&gt;对于分布式 KV 后端而言，这类批量化操作可以更充分地发挥后端的并发写入能力。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;以下是在 100,000 个文件 flat 目录下，使用 &lt;code&gt;juicefs rmr --threads 16&lt;/code&gt; 的测试结果，可以看到批量删除在不同元数据后端上均带来了明显提升，其中 TiKV 和 Redis 的收益更为显著。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;批量删除的吞吐提升&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;不同元数据后端下批量删除的吞吐提升&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;h2&gt;02 克隆：从逐条复制到批量引用&lt;/h2&gt;
&lt;p&gt;JuiceFS clone 常用于快速生成文件或目录副本，例如训练数据集版本管理、实验数据快照和大规模目录复制等场景。其高效之处在于创建副本时不会立即拷贝底层数据块，而是在元数据层创建新的文件记录，并复用源文件已有的数据块引用；后续只有副本发生写入时，系统才会为被修改的部分分配新的数据块。因此，clone 可以减少完整复制带来的时间和存储开销。&lt;/p&gt;
&lt;p&gt;对于克隆大目录，与删除类似，逐文件处理会导致大量短事务和网络交互，由此产生大量元数据操作。&lt;strong&gt;批量克隆的核心是将同一目录下多个文件的克隆操作合并为一次批量事务。&lt;/strong&gt;递归克隆目录时，系统会流式分批读取目录条目，将每批中的所有非目录条目收集后一次性批量克隆。&lt;/p&gt;
&lt;p&gt;实现上的一个关键优化是"inode 预分配"：在进入事务之前，系统先通过 nextInode 为所有待克隆条目预先分配好目标 inode。这避免了在事务内部频繁申请 inode 导致锁竞争。进入事务后，系统批量查询所有源文件属性（带行锁），构建好所有目标 node、edge、chunk、symlink、xattr 的插入数据，然后一次性批量插入。&lt;/p&gt;
&lt;p&gt;批量克隆在不同元数据后端中的实现仍然会利用各自的批量写入能力，这一节不再展开写入细节。不同后端的性能提升幅度不仅取决于事务模型和网络交互成本，也与批量写入 node、edge、chunk 引用等元数据记录的效率有关。&lt;/p&gt;
&lt;p&gt;具体测试结果如下表所示，在包含十万个文件的 flat 目录上，我们使用 &lt;code&gt;juicefs clone&lt;/code&gt; 对比了优化前后的克隆性能，MySQL 后端提升最为显著，约 24 倍；Redis 后端约 5 倍，TiKV 后端约 2 倍。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;批量克隆的吞吐提升&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;不同元数据后端下批量克隆的吞吐提升&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;h2&gt;03 Redis 客户端缓存：将热点元数据缓存在本地&lt;/h2&gt;
&lt;p&gt;在高并发元数据访问场景，如 AI 训练数据集加载、大规模容器启动等，客户端与 Redis 元数据引擎之间的网络往返是主要的性能瓶颈。&lt;/p&gt;
&lt;p&gt;以内核 VFS 的路径解析为例：当进程执行 &lt;code&gt;open("/mnt/jfs/dataset/images/cat.jpg")&lt;/code&gt; 时，VFS 层需要逐级解析每个路径分量——先 lookup &lt;code&gt;dataset&lt;/code&gt;，再 lookup &lt;code&gt;images&lt;/code&gt;，最后 lookup &lt;code&gt;cat.jpg&lt;/code&gt;。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;内核 VFS 路径解析&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;内核 VFS 路径解析&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;如果 &lt;code&gt;images&lt;/code&gt; 目录下包含数十万个文件，而训练任务需要随机访问其中的文件，那么每次 lookup 都需要向 Redis 发起一次 GET 请求。在高并发场景下，这会造成大量的网络往返和 Redis CPU 消耗。&lt;strong&gt;即使 Redis 本身单次查询只需几十微秒，但加上网络延迟后，每次 lookup 可能就需要几百微秒甚至毫秒级。当数千个训练进程同时进行文件访问时，这个开销会被急剧放大。&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;实现原理：基于 Redis 6.0 客户端缓存机制&lt;/h3&gt;
&lt;p&gt;Redis 6.0 引入了客户端缓存（Client-Side Caching）功能，允许客户端在本地缓存热点键值，并由 Redis 服务器在键被修改时主动推送失效通知。JuiceFS 基于这一能力，将两类核心元数据缓存在客户端内存中：&lt;/p&gt;
&lt;p&gt;第一类是 &lt;strong&gt;inode 属性缓存&lt;/strong&gt;。以 inode 号为键，缓存该文件的完整属性数据（类型、大小、权限、时间戳等）。这类缓存通过 Redis 客户端驱动层的钩子机制透明实现：查询时自动先检查本地缓存，命中则直接返回，完全跳过网络请求；修改时则自动清除对应缓存，业务逻辑无需感知。&lt;/p&gt;
&lt;p&gt;第二类是 &lt;strong&gt;目录条目缓存（entry cache）&lt;/strong&gt;。以"父目录 inode + 路径分隔符 + 文件名"为键，缓存目录 lookup 的结果。与 inode 属性缓存不同，这类缓存的检查逻辑内嵌于目录查找路径本身，而非通过驱动层透明拦截。当某个目录的条目失效时，通过前缀匹配清除该目录下的所有相关缓存。这样一来，路径解析或重复访问同一目录下的热点条目时可以直接命中本地缓存。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;引入客户端缓存后，核心挑战在于多客户端挂载场景下的元数据一致性维护。&lt;/strong&gt;当多个客户端共享同一个 JuiceFS 文件系统时，某一客户端对文件或目录执行创建、删除、重命名或属性更新等操作后，其他客户端本地缓存中的相关 inode 属性或目录项结果可能随之失效。如果缺少有效的缓存失效机制，后续访问就可能命中过期元数据，导致客户端观察到的目录项或文件属性与后端元数据状态不一致。&lt;/p&gt;
&lt;p&gt;为此，JuiceFS 基于 Redis 的客户端缓存机制，引入 Tracking 与广播失效（BCAST）模式。客户端连接 Redis 后，会声明需要跟踪的元数据 key 前缀；当这些 key 被修改时，Redis 会向相关客户端发送失效通知。客户端收到通知后，会根据 key 类型清理对应的 inode 属性缓存或 entry cache，使后续访问重新从元数据引擎获取最新结果。&lt;/p&gt;
&lt;p&gt;此外，客户端初始化时，JuiceFS 会对挂载点根目录下的元数据进行预热。由于这部分文件通常访问频率最高，实测表明该优化能够有效提升整体访问性能。&lt;/p&gt;
&lt;p&gt;通过上述机制，热点元数据可以在客户端本地复用；一旦相关元数据发生变化，对应缓存会被及时淘汰，从而降低过期元数据被继续使用的风险。&lt;/p&gt;
&lt;h3&gt;适用场景与注意事项&lt;/h3&gt;
&lt;p&gt;Redis 客户端缓存最适合读多写少、热点元数据重复访问明显的场景，例如 AI 训练数据集加载——训练过程中数据集通常只读不写，任务会反复访问相同目录和文件，因此 inode 属性缓存和 entry cache 更容易命中，进而减少重复 lookup 和远端元数据查询。&lt;/p&gt;
&lt;p&gt;如果客户端与 Redis 元数据引擎之间存在较高网络延迟，例如跨可用区部署，本地缓存的收益会更加明显。&lt;/p&gt;
&lt;p&gt;使用该能力时，需要确保 Redis 版本为 6.0 及以上。默认缓存过期时间为 1 分钟，用于在网络闪断、连接异常等情况下为失效通知机制提供兜底，避免过期元数据长期保留在客户端本地缓存中。对于强一致性行更高的场景，可以根据实际需求缩短缓存过期时间，或关闭客户端缓存，以降低读取过期元数据的风险。&lt;/p&gt;
&lt;h2&gt;04 小结&lt;/h2&gt;
&lt;p&gt;这三项优化分别覆盖了元数据的写、复制和读三条路径：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;批量删除&lt;/strong&gt;将同一目录下的多次独立 unlink 合并为一次批量事务  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;批量克隆&lt;/strong&gt;将同一目录下的多次独立 clone 合并为一次批量事务  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Redis 客户端缓存&lt;/strong&gt;在客户端本地缓存热点元数据，将读操作延迟从网络级降到内存级，通过广播失效保证多客户端一致性。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其中 BatchUnlink 和 BatchClone 都是内部接口，用户无需直接调用，只需选择正确的操作方式即可命中优化（例如，删除大目录用 &lt;code&gt;juicefs rmr&lt;/code&gt;，复制目录用 &lt;code&gt;juicefs clone&lt;/code&gt;）。&lt;/p&gt;
&lt;p&gt;需要注意的是，批量操作的核心是把同一目录下的普通文件合并为一次批量事务；子目录则通过并发 goroutine 递归处理。因此，越是大型的目录，优化的收益越明显。&lt;/p&gt;
&lt;p&gt;以上优化均已在 JuiceFS 社区版 1.4 中可用，升级客户端版本即可获得性能收益。&lt;/p&gt;&lt;/div&gt;</description><pubDate>Wed, 03 Jun 2026 09:04:50 +0000</pubDate><guid>https://www.juicefs.com/zh-cn/blog/engineering/juicefs-massive-metadata-optimization</guid></item><item><title>共绩科技：跨云弹性推理场景下，模型分发如何跟上算力调度</title><link>https://www.juicefs.com/zh-cn/blog/user-stories/gongji-tech-cross-cloud-elastic-inference-model-distribution</link><description>&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;共绩科技 2023 年成立于清华，面向 AIGC 企业和科研机构提供算力平台与 MaaS 服务，致力于缓解弹性算力需求与供给之间的错配。平台通过聚合 IDC 闲置资源和边缘资源，以容器化服务为主，为 AI 推理、视频渲染、数据处理和数据合成等波动性场景提供可快速调度的算力资源。&lt;/p&gt;
&lt;p&gt;在跨云弹性推理场景中，计算任务可以调度到不同地域、云环境和集群，但模型文件和业务数据体积较大，难以像计算资源一样快速迁移。尤其是在线推理场景，模型仓库以读为主且访问频繁，存储访问能力会直接影响服务启动、弹性扩容和请求延迟。&lt;/p&gt;
&lt;p&gt;为此，共绩科技基于 JuiceFS 封装了“对象存储加速”方案，将用户已有对象存储接入弹性推理集群，并通过统一命名空间、元数据导入、FUSE 挂载、分布式缓存和数据预热，提升模型仓库在跨云、跨集群环境中的访问效率。以一家头部文生图模型社区实践为例，该方案支撑了几十 TB 级模型仓库、checkpoint 与 LoRA 动态加载，以及高峰期数百卡弹性资源扩容，并将弹性集群的额外延迟控制在客户验收范围内。&lt;/p&gt;
&lt;h2&gt;01 弹性需求广泛存在，供给却难以匹配&lt;/h2&gt;
&lt;p&gt;随着 AI 应用快速发展，算力需求持续增长，但不同场景的资源使用特征并不相同。&lt;strong&gt;相比训练任务相对稳定的资源需求，AI 推理、数据处理和数据合成等场景通常具有更强的波动性&lt;/strong&gt;：办公类应用可能在白天流量更高，娱乐类应用可能在傍晚或周末迎来高峰；项目制的数据处理任务则可能在短时间内集中消耗大量算力，任务结束后又进入空窗期。对于中小团队或探索型业务而言，弹性算力还能帮助其更清晰地评估单次请求成本与商业收益之间的关系。&lt;/p&gt;
&lt;p&gt;但在供给侧，算力基础设施建设属于重资产投入。资源方通常并非不具备弹性服务能力，而是更倾向于通过长期整租回收成本、降低风险。这使得市场上低价、稳定、弹性三者难以同时满足：整租资源价格较低且供应稳定，但缺乏弹性；Spot 资源价格低且具备弹性，但供应不确定；On-demand 资源弹性和稳定性较好，但成本较高。在中国市场，这种矛盾进一步表现为交易主要集中在整租订单，弹性资源供给占比较低。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;弹性算力供给的三角权衡&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;弹性算力供给的三角权衡&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;共绩科技希望解决的，正是弹性算力需求与供给之间的错配问题。&lt;strong&gt;通过聚合 IDC 闲置资源及更分散的边缘资源，平台以容器化服务为主，为 AI 推理、视频渲染、数据处理和数据合成等场景提供可快速调度的算力资源&lt;/strong&gt;，在较低资源成本基础上，帮助用户在业务高峰时快速拉起任务、调度至不同集群并承接弹性需求。资源方也可以在整租之外，提高闲置资源的利用率和变现效率。&lt;/p&gt;
&lt;h2&gt;02 算力可以调度，存储如何跟上？&lt;/h2&gt;
&lt;p&gt;随着弹性算力平台的发展，计算资源的调度相对容易实现。容器镜像可以通过镜像仓库和分发网络同步到不同集群，计算任务可以由调度系统在不同资源池中拉起，业务流量也可以通过统一接入层和流量治理能力进行分发。&lt;/p&gt;
&lt;p&gt;但模型和数据文件通常体积较大，跨云、跨集群迁移成本高、耗时长，难以匹配计算资源秒级拉起和释放的节奏。因此，&lt;strong&gt;在跨云弹性推理架构中，真正限制系统弹性的往往不是算力调度，而是数据和模型的分发效率&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;不同业务场景对存储的要求并不相同。&lt;strong&gt;第一类是模型训练、开发和调试场景&lt;/strong&gt;。这类场景通常涉及复杂的读写需求，包括代码仓库、模型文件、实验结果和中间状态等。同时，开发调试对环境稳定性要求很高，用户无法接受主机频繁切换导致状态丢失。因此，在这类场景中，平台通常会为用户提供长期稳定的计算资源和运行环境，相关存储需求也可以通过集群内已有的稳定存储体系来承载。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第二类是数据处理场景&lt;/strong&gt;。这类业务又可以分为两种情况：如果单次数据处理的业务价值较高，能够覆盖跨云网络传输成本，就可以直接构建数据处理流水线，从 S3 或其他对象存储持续拉取数据，在计算集群内处理后再流式写回。此时系统不必依赖大规模本地存储。如果数据规模更大，或者单次处理的经济价值较低，本地存储更多也只是一次性缓存，数据在处理流程中流过即可，并不需要长期沉淀在计算集群内。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;真正更具挑战的是在线推理场景&lt;/strong&gt;。在线推理业务不能接受服务中断，但弹性算力平台所使用的资源可能来自闲置资源池，存在被撤出的可能。一旦某个机房或集群资源不可用，平台必须能够及时将任务迁移到其他供应商或其他集群。这意味着不仅计算任务要能够迁移，模型文件和相关存储访问能力也必须能够同步迁移。&lt;/p&gt;
&lt;p&gt;在线推理虽然对服务连续性和跨集群迁移能力要求更高，但它的存储访问模式也相对更明确。与训练、开发和调试场景相比，推理业务通常以读为主，核心需求集中在高效加载模型、读取模型权重和访问模型仓库上。对于大型模型和在线应用而言，模型加载速度直接影响服务启动时间、弹性扩容效率和请求响应稳定性。因此，推理场景并不适合简单沿用传统读写混合型存储架构，而更适合围绕模型分发、只读访问和缓存加速进行专门优化。&lt;/p&gt;
&lt;p&gt;此外，弹性算力平台通常并不承载用户完整的业务系统。用户的主云账号、业务数据库、模型管理系统，甚至部分固定算力资源，往往已经存在于其他云或自有环境中。平台要接入用户业务，就必须与其现有模型仓库和模型管理流程兼容，不能要求用户重新迁移整套系统。&lt;/p&gt;
&lt;p&gt;因此，&lt;strong&gt;要支撑跨云弹性推理，需要的不只是计算调度能力，而是一套面向模型推理场景的跨云高性能存储与模型分发方案&lt;/strong&gt;：既要支持大模型仓库的托管和高性能读取，又要适配用户已有的模型管理体系，并能够在资源跨云、跨集群迁移时提供稳定的数据访问能力。&lt;/p&gt;
&lt;h2&gt;03 Why JuiceFS：跨云统一访问、强一致元数据与高性能缓存&lt;/h2&gt;
&lt;p&gt;面对跨云弹性推理场景，存储系统需要同时满足几个条件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;能够在不同云和不同集群之间提供统一访问入口，支持共享读写和统一元数据管理；&lt;/li&gt;
&lt;li&gt;能够兼容用户已有的对象存储和模型仓库，避免用户迁移现有数据；&lt;/li&gt;
&lt;li&gt;同时还要具备较低的运维复杂度和较好的读性能。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在存储方案选型过程中，我们曾评估过 Ceph。Ceph 技术成熟，适合在单一数据中心或相对稳定的资源域内构建统一存储。但在跨云弹性推理场景下，Ceph 对网络稳定性和运维能力要求较高，整体接入成本相对更高，因此没有作为最终方案。&lt;/p&gt;
&lt;p&gt;Alluxio 也曾进入评估范围。但在多云环境下，多个集群需要并发访问同一份底层对象存储数据，且业务并非完全只读，也存在少量写入。该场景对数据强一致性要求较高，因此 Alluxio 最终未作为生产方案。&lt;/p&gt;
&lt;p&gt;最终选择 JuiceFS，主要是因为它以对象存储作为数据底座，并通过独立元数据服务提供统一命名空间和一致的文件系统视图，能够让多个集群以文件系统方式访问同一份模型数据。这种架构既适合跨云、跨集群的模型分发和共享读取，也能够较好兼容用户已有的对象存储和模型仓库，降低数据迁移和业务接入成本。&lt;/p&gt;
&lt;p&gt;进一步采用 JuiceFS 企业版，则主要看重其分布式缓存能力和元数据托管能力。在这个场景中，JuiceFS 的价值并不只是提供一个文件系统接口，而是把对象存储、统一命名空间、元数据管理和缓存加速组合成一套更适合跨云弹性推理的存储访问层。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;JuiceFS 企业版架构图&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;JuiceFS 企业版架构图&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;h2&gt;04 实践方案：基于JuiceFS 的对象存储加速&lt;/h2&gt;
&lt;p&gt;基于 JuiceFS，平台封装了“对象存储加速”产品，用于将用户已有的对象存储接入弹性推理集群，并以高性能文件系统的形式提供给业务使用。整体流程如下。&lt;/p&gt;
&lt;p&gt;首先是创建文件系统。用户提供对象存储的访问凭证，例如 S3 兼容存储的 AK/SK。凭证权限可以根据业务需求配置为只读或读写，平台基于该对象存储创建对应的 JuiceFS 文件系统。&lt;/p&gt;
&lt;p&gt;其次是导入元数据。平台通过 JuiceFS import 能力扫描对象存储中的文件元数据，并将其导入 JuiceFS 元数据服务。这样，用户原本存放在对象存储中的模型文件，就可以在 JuiceFS 中以文件系统目录的形式被访问。&lt;/p&gt;
&lt;p&gt;第三是建立缓存组。在可能承载任务的各个集群内，平台会建立 JuiceFS Cache Group，形成分布式缓存组。任务运行前，平台可以先对模型文件进行数据预热，将热点数据提前缓存到目标集群，减少推理服务启动时从远端对象存储拉取数据的耗时。&lt;/p&gt;
&lt;p&gt;第四是挂载到业务 Pod。用户业务运行时，平台通过 FUSE 客户端将 JuiceFS 文件系统挂载到业务 Pod 中。对于应用而言，模型文件表现为本地文件系统路径，因此通常不需要改造原有的模型读取逻辑。&lt;/p&gt;
&lt;p&gt;第五是启用节点缓存。除了集群级 Cache Group，FUSE 客户端所在节点也可以提供本地缓存，用于提升重复读取和模型加载性能，进一步降低对远端对象存储的直接访问。&lt;/p&gt;
&lt;p&gt;这个“对象存储加速”产品，本质上是将 JuiceFS 的元数据导入、分布式缓存、数据预热和 FUSE 挂载流程产品化，使用户已有的对象存储能够以更接近本地文件系统的方式服务于跨云推理任务。&lt;/p&gt;
&lt;p&gt;此外，JuiceFS 的 Cache Group 与文件系统访问入口相对独立。这个特性一方面会增加平台侧的管理复杂度，因为平台需要同时管理文件系统、缓存组、挂载入口和任务调度之间的关系；另一方面，也为后续按集群、按用户或按业务场景进行缓存隔离、独立调度和精细化管理提供了基础。&lt;/p&gt;
&lt;h2&gt;05 业务实战：头部文生图模型社区&lt;/h2&gt;
&lt;h3&gt;场景、挑战与验收标准&lt;/h3&gt;
&lt;p&gt;在这套对象存储加速方案中，一个比较典型的实践案例来自国内头部文生图模型社区，其托管了几十 TB 规模的模型数据，既包括体积较大的 checkpoint 基座模型，也包括数量更多、体积相对较小的 LoRA 模型。在实际推理过程中，业务通常需要先加载 checkpoint，再加载一个或多个 LoRA，完成组合推理。&lt;/p&gt;
&lt;p&gt;该公司自身已经拥有较大规模的算力资源，规模达到数千卡级别。但由于其面向创意设计等生产场景，&lt;strong&gt;业务负载具有明显波动性，整体平均利用率不到 50%。在工作日的上午和下午高峰时段，负载甚至可能达到常规承载水位的 140%，导致服务体验下降&lt;/strong&gt;。因此，客户需要一种高度弹性的算力供给方式。&lt;/p&gt;
&lt;p&gt;共绩为其提供的是一种高弹性的资源模式：仅在工作日高峰时段，即上午 10:00–12:00 和下午 14:00–18:00，提供数百卡规模的算力支持，其余时间资源规模降为 0。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;扩缩容效果&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;闲时调度在业务峰谷场景中的扩缩容效果&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;这意味着平台需要在分钟级时间窗口内完成数百卡资源的快速扩容，而在非高峰时段完全不占用资源。对客户而言，这种模式可以在峰值时段获得大量算力支持，同时避免为低谷资源付费；对平台而言，也可以更高效地利用闲置算力资源，具备较好的商业价值。&lt;/p&gt;
&lt;p&gt;但这一场景的技术挑战也非常突出。首先，这类几十 TB 级模型仓库无法简单复制到每一个弹性集群。其次，推理服务并不是在启动时一次性加载全部模型，而是会随着用户请求持续发生模型读取和切换，访问频率较高。这意味着对象存储加速方案不仅要支持大规模模型仓库访问，还要在持续动态加载场景下保持稳定的读取性能。&lt;/p&gt;
&lt;p&gt;与此同时，该公司对性能要求非常严格。在验收过程中，会将部分生产流量引入弹性集群进行测试，并要求弹性集群与其自有集群相比，推理耗时的中位数和平均值差异都必须控制在 2 秒以内。考虑到单次推理耗时本身在几十秒量级，这一要求意味着对象存储加速方案几乎不能引入额外延迟。在最初几轮测试中，弹性集群的推理耗时中位数和平均值均比客户自有集群高出约 10 秒，未能通过验收。&lt;/p&gt;
&lt;h3&gt;性能优化：降低弹性集群的额外延迟&lt;/h3&gt;
&lt;p&gt;优化首先从中位数入手。&lt;strong&gt;中位数偏高意味着有相当比例的请求都存在性能损耗，而不是少量偶发请求造成的长尾问题&lt;/strong&gt;。通过 JuiceFS 监控发现，集群缓存命中率没有达到预期。在当前架构下，一旦缓存未命中，请求就需要跨公网访问客户在阿里云上的对象存储进行回源，这会显著拉高模型加载耗时，并进一步影响推理请求延迟。&lt;/p&gt;
&lt;p&gt;针对这一问题，平台利用 JuiceFS Cache Group 的隔离能力，为该客户分配专属缓存节点，并预留充足缓存空间，对核心模型数据进行充分预热。完成预热后，核心模型访问路径基本实现 100% 缓存命中，有效避免了跨公网回源带来的性能损失。&lt;/p&gt;
&lt;p&gt;第二个影响中位数的因素是元数据访问延迟。由于平台采用跨集群统一架构，元数据服务需要通过公网访问，例如使用 JuiceFS 云服务或部署在其他云主机上，因此元数据访问延迟会影响整体模型读取性能。&lt;/p&gt;
&lt;p&gt;针对这一问题，平台采取了两项措施：一是开启 JuiceFS 的 open cache，将元数据尽可能缓存到本地内存中。由于该场景以只读访问为主，适合通过缓存降低元数据访问开销。二是优化集群网络限流策略。尽管平台无法直接控制边缘机房的网络设备，但可以通过节点级限流，避免单个节点占满带宽，从而提升整体网络稳定性。完成这些优化后，集群整体性能明显提升，中位数逐步达到客户要求。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;当中位数达标后，平均值仍然存在偏差。这说明系统中仍存在长尾请求，即少量请求耗时显著高于正常水平，并拉高了整体平均值&lt;/strong&gt;。进一步分析发现，这主要与节点本地缓存，也就是 FUSE 缓存配额有关。由于缓存容量较小，相比客户自有集群，弹性集群更容易发生缓存换出，导致部分请求需要重新加载模型数据，从而拉高平均推理耗时。针对这一问题，平台在生产环境中扩大了 FUSE 本地缓存配额，降低缓存换出频率，改善长尾表现，最终使平均值指标也满足验收要求。经过上述优化，系统顺利通过验收，并稳定运行。&lt;/p&gt;
&lt;h3&gt;多租户缓存治理&lt;/h3&gt;
&lt;p&gt;场景验证通过后，这套能力也进一步进入多租户运行阶段。随着不同租户按时间片复用同一批弹性节点，新的问题开始暴露出来，即节点缓存竞争问题。&lt;/p&gt;
&lt;p&gt;在弹性资源模型下，FUSE 客户端退出时不会主动清理节点缓存。这个设计在单租户场景下是合理的，因为历史缓存可以被后续任务复用，从而提高命中率。&lt;strong&gt;但在多租户场景下，前一个租户的数据可能长期占用节点缓存空间，使后续租户无法获得足够缓存资源，最终不得不回源访问对象存储，导致性能明显下降&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;为了解决这一问题，共绩在每个节点上部署了独立的守护进程，由该进程在业务 FUSE 客户端启动前执行全局缓存垃圾回收。具体策略参考 JuiceFS FUSE 客户端的实现，采用 2-random 策略，在回收效率和性能之间取得平衡。同时，各节点之间通过 Kubernetes 分布式锁进行协调，只有抢到锁的客户端才执行 GC，避免多个客户端同时回收缓存，从而造成额外的网络和 I/O 压力。&lt;/p&gt;
&lt;p&gt;通过这一机制，我们有效缓解了多租户场景下缓存资源被历史任务占用的问题，使不同租户在共享弹性资源时，仍然能够获得相对稳定的缓存性能。&lt;/p&gt;
&lt;h2&gt;06 结语&lt;/h2&gt;
&lt;p&gt;弹性算力要稳定承接生产流量，不能只依赖计算调度，还需要模型数据和热点数据在跨云、跨集群环境中保持稳定访问。&lt;/p&gt;
&lt;p&gt;基于 JuiceFS，共绩科技将对象存储、统一命名空间、元数据管理、分布式缓存和 FUSE 挂载能力组合起来，形成了一套面向弹性推理场景的对象存储加速方案。它并不是简单地把对象存储挂载成文件系统，而是围绕模型推理的访问模式，提供可预热、可缓存、可隔离、可治理的数据访问层。&lt;/p&gt;
&lt;p&gt;以上是共绩科技在弹性算力与跨云存储加速方向上的阶段性探索和实践。随着 AI 推理场景持续演进，模型分发、缓存治理和多集群数据访问仍会不断出现新的工程问题。我们也希望与更多开发者、AI 应用团队和基础设施从业者交流，共同探讨弹性算力场景下更稳定、更高效的数据访问方案。&lt;/p&gt;&lt;/div&gt;</description><pubDate>Wed, 27 May 2026 03:43:05 +0000</pubDate><guid>https://www.juicefs.com/zh-cn/blog/user-stories/gongji-tech-cross-cloud-elastic-inference-model-distribution</guid></item><item><title>降低数据存储成本：JuiceFS v1.4 分层存储设计解析</title><link>https://www.juicefs.com/zh-cn/blog/engineering/juicefs-v1-4-tiered-storage-design-reduce-cost</link><description>&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;JuiceFS 社区版 1.4 增强了分层存储能力，支持以单文件或目录为粒度指定对象存储类型，使用户可以在文件系统语义下管理不同数据的存储层级。本文将围绕这一能力，介绍其应用背景、方案演进、使用模型、实现思路以及后续演进方向。&lt;/p&gt;
&lt;h2&gt;01 核心背景&lt;/h2&gt;
&lt;p&gt;在实际业务中，不同文件的访问频率和性能要求往往差异明显：一部分数据需要被频繁读取或写入，对访问延迟和吞吐较为敏感；另一部分数据写入后很少再被访问，更多关注长期保存成本。分层存储正是为了解决这一问题，即根据数据的访问特征，将其匹配到更合适的存储层，从而兼顾性能与成本。&lt;/p&gt;
&lt;p&gt;通常可以根据访问特征将数据分为几类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;热数据&lt;/strong&gt;：访问频繁，通常要求低延迟和较高吞吐；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;低频数据&lt;/strong&gt;：访问频率较低，但在需要时仍希望能够快速读取；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;归档数据&lt;/strong&gt;：主要用于长期保存，访问频率极低，可以接受一定的恢复等待时间，以换取更低的存储成本。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对象存储本身已经提供了类似的分层能力。以 Amazon S3 为例，S3 Standard 适合频繁访问的数据，S3 Standard-IA 适合低频访问但仍需要毫秒级读取的数据，而 Glacier / Deep Archive 更适合长期归档场景。不同存储类型在访问延迟、最低存储时长和费用模型上存在差异。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-table block-table"&gt;

&lt;table&gt;
    
        &lt;caption&gt;S3 主要存储类对比表&lt;/caption&gt;
    
    
        &lt;thead&gt;
            &lt;tr&gt;
                
                    
                        
                        
                            &lt;th scope="col"  &gt;
                                
                                    
                                        存储类型
                                    
                                
                            &lt;/th&gt;
                        
                    
                
                    
                        
                        
                            &lt;th scope="col"  &gt;
                                
                                    
                                        使用案例
                                    
                                
                            &lt;/th&gt;
                        
                    
                
                    
                        
                        
                            &lt;th scope="col"  &gt;
                                
                                    
                                        首字节延迟
                                    
                                
                            &lt;/th&gt;
                        
                    
                
                    
                        
                        
                            &lt;th scope="col"  &gt;
                                
                                    
                                        最低存储持续时间费用
                                    
                                
                            &lt;/th&gt;
                        
                    
                
            &lt;/tr&gt;
        &lt;/thead&gt;
    
    &lt;tbody&gt;
        
            
                &lt;tr&gt;
                    
                        
                            
                            
                                
                                    &lt;td  &gt;
                                        
                                            
                                                S3 Standard
                                            
                                        
                                    &lt;/td&gt;
                                
                            
                        
                    
                        
                            
                            
                                
                                    &lt;td  &gt;
                                        
                                            
                                                用于对经常访问的数据进行通用存储
                                            
                                        
                                    &lt;/td&gt;
                                
                            
                        
                    
                        
                            
                            
                                
                                    &lt;td  &gt;
                                        
                                            
                                                毫秒
                                            
                                        
                                    &lt;/td&gt;
                                
                            
                        
                    
                        
                            
                            
                                
                                    &lt;td  &gt;
                                        
                                            
                                                不适用
                                            
                                        
                                    &lt;/td&gt;
                                
                            
                        
                    
                &lt;/tr&gt;
            
        
            
                &lt;tr&gt;
                    
                        
                            
                            
                                
                                    &lt;td  &gt;
                                        
                                            
                                                S3 Standard-IA
                                            
                                        
                                    &lt;/td&gt;
                                
                            
                        
                    
                        
                            
                            
                                
                                    &lt;td  &gt;
                                        
                                            
                                                需要毫秒级访问的不经常访问的数据
                                            
                                        
                                    &lt;/td&gt;
                                
                            
                        
                    
                        
                            
                            
                                
                                    &lt;td  &gt;
                                        
                                            
                                                毫秒
                                            
                                        
                                    &lt;/td&gt;
                                
                            
                        
                    
                        
                            
                            
                                
                                    &lt;td  &gt;
                                        
                                            
                                                30 天
                                            
                                        
                                    &lt;/td&gt;
                                
                            
                        
                    
                &lt;/tr&gt;
            
        
            
                &lt;tr&gt;
                    
                        
                            
                            
                                
                                    &lt;td  &gt;
                                        
                                            
                                                S3 Glacier Deep Archive
                                            
                                        
                                    &lt;/td&gt;
                                
                            
                        
                    
                        
                            
                            
                                
                                    &lt;td  &gt;
                                        
                                            
                                                存档非常少访问且成本非常低的数据
                                            
                                        
                                    &lt;/td&gt;
                                
                            
                        
                    
                        
                            
                            
                                
                                    &lt;td  &gt;
                                        
                                            
                                                小时
                                            
                                        
                                    &lt;/td&gt;
                                
                            
                        
                    
                        
                            
                            
                                
                                    &lt;td  &gt;
                                        
                                            
                                                180 天
                                            
                                        
                                    &lt;/td&gt;
                                
                            
                        
                    
                &lt;/tr&gt;
            
        
    &lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;对于构建在对象存储之上的 JuiceFS 来说，关键是将这些能力转化为文件系统层面的分层管理能力：用户按文件、目录或数据集设置存储层级，JuiceFS 负责映射到底层对象存储，并处理写入、迁移和归档恢复等操作。&lt;/p&gt;
&lt;h2&gt;02 JuiceFS 分层方案的演进&lt;/h2&gt;
&lt;p&gt;JuiceFS 分层能力的演进，本质上是从“被动不感知对象存储类型”，逐步发展到“可在文件和目录粒度管理主动存储层级”。&lt;/p&gt;
&lt;p&gt;在 v1.1 以前，JuiceFS 尚未提供存储类型配置能力。用户虽然可以在对象存储侧手动调整对象的 Storage Class，但这些变化不会被 JuiceFS 在文件系统层面统一感知和管理。对于标准层、低频层等支持实时访问的对象，通常不会影响正常读写；但如果对象被转入归档类存储，则可能因无法直接读取而导致访问异常。&lt;/p&gt;
&lt;p&gt;从 v1.1 开始，JuiceFS 支持通过 &lt;code&gt;--storage-class&lt;/code&gt; 设置对象存储类型。例如，可以在 format 时指定文件系统的默认 Storage Class，也可以在 mount 时覆盖当前挂载点写入数据所使用的存储类型。这使 JuiceFS 开始具备使用对象存储分层能力的基础，但配置粒度仍主要停留在文件系统默认值或挂载点级别，无法针对具体目录、单个文件或不同业务数据集进行精细化管理。&lt;/p&gt;
&lt;p&gt;v1.4 进一步将分层能力推进到文件和目录粒度。用户可以根据数据冷热程度，为单个文件或目录设置对应的存储层级；当目录设置了特定层级后，后续在该目录下新建的文件和子目录也可以自动继承这一配置。相比此前的默认值或挂载点级设置，v1.4 更适合按项目、目录、数据集或文件冷热程度进行分层管理。&lt;/p&gt;
&lt;h2&gt;03 分层存储如何配置&lt;/h2&gt;
&lt;p&gt;JuiceFS v1.4 分层存储的关键在于：将对象存储的 Storage Class 转化为文件系统可管理的存储在使用层面，JuiceFS v1.4 分层存储可以理解为两个步骤：&lt;strong&gt;先建立 Tier ID 与对象存储 Storage Class 的映射关系，再将文件或目录设置到对应的 Tier ID&lt;/strong&gt;。通过这一方式，用户可以按文件、目录或数据集组织分层策略，而不需要在每次写入时直接指定底层对象的存储类型。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;映射示意图&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;Tier ID 与 Storage Class 映射示意图&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;例如，可以将 Tier ID 1–3 分别映射到不同的对象存储类型：&lt;/p&gt;
&lt;pre class="codehilite"&gt;&lt;code class="language-shell"&gt;juicefs config redis://localhost --tier-id 1 --tier-sc STANDARD_IA -y
juicefs config redis://localhost --tier-id 2 --tier-sc INTELLIGENT_TIERING -y
juicefs config redis://localhost --tier-id 3 --tier-sc GLACIER_IR -y
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;完成映射后，可以为单个文件或目录设置存储层级：&lt;/p&gt;
&lt;pre class="codehilite"&gt;&lt;code class="language-shell"&gt;juicefs tier set redis://localhost --id 1 /path/to/file
juicefs tier set redis://localhost --id 2 /path/to/dir
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;目录级设置具有继承语义。为目录设置 &lt;code&gt;tier-id&lt;/code&gt; 后，后续在该目录下新建的文件或子目录会自动继承父目录的存储层级；如果需要处理目录下已有的数据，则可以使用 &lt;code&gt;-r&lt;/code&gt; 参数递归设置：&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;继承与存量递归&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;目录继承与存量递归设置&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;pre class="codehilite"&gt;&lt;code class="language-shell"&gt;juicefs tier set redis://localhost --id 2 /path/to/dir -r
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;对于 Glacier 等归档类存储，读取前通常需要先发起恢复请求：&lt;/p&gt;
&lt;pre class="codehilite"&gt;&lt;code class="language-shell"&gt;juicefs tier restore redis://localhost /path/to/dir -r
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;04 技术实现原理&lt;/h2&gt;
&lt;p&gt;从实现角度看，JuiceFS v1.4 分层存储的关键，是将文件或目录的分层信息纳入元数据管理，并在写入、迁移和读取流程中根据 &lt;code&gt;tier-id&lt;/code&gt; 选择相应的对象存储行为。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;各行为流程&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;写入、迁移与归档读取流程&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;&lt;strong&gt;元数据设计&lt;/strong&gt;
JuiceFS 使用 &lt;code&gt;tier-id&lt;/code&gt; 记录文件或目录所属的存储层级。&lt;code&gt;tier-id&lt;/code&gt; 取值为 0 时，表示使用默认存储层；取值为 1–3 时，则对应用户配置的对象存储 Storage Class。&lt;/p&gt;
&lt;p&gt;这样，存储层级不再只是对象存储侧的外部状态，而是成为 JuiceFS 可以在文件系统语义下感知和管理的元数据信息。后续写入新数据、迁移存量数据或检查文件状态时，JuiceFS 都可以基于这一元数据判断目标存储类型。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;存量数据迁移&lt;/strong&gt;
对于已有数据，修改存储层级不仅需要更新元数据中的 &lt;code&gt;tier-id&lt;/code&gt;，还需要改变对象存储中已有对象的实际 Storage Class。递归设置目录时，JuiceFS 会处理目标目录下的文件和子目录，并通过对象存储的复制能力，将已有对象迁移到新的存储类型。&lt;/p&gt;
&lt;p&gt;如果只是修改某个 &lt;code&gt;tier-id&lt;/code&gt; 对应的 &lt;code&gt;tier-sc&lt;/code&gt; 映射，已有对象的实际存储类型不会自动变化。此时需要使用 &lt;code&gt;tier set --force&lt;/code&gt; 显式触发变更，使存量对象改为新的 Storage Class。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;写入流程&lt;/strong&gt;
新文件写入时，JuiceFS 会根据文件自身或父目录继承得到的 &lt;code&gt;tier-id&lt;/code&gt;，确定数据应写入的对象存储类型。对于已经设置存储层级的目录，新建数据可以直接进入对应的存储层，避免先写入默认层后再迁移。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;读取流程&lt;/strong&gt;
对于标准层、低频层等支持实时访问的存储类型，读取过程对业务基本透明，JuiceFS 可以按正常流程从对象存储中读取数据。&lt;/p&gt;
&lt;p&gt;对于 Glacier、Deep Archive 等归档类存储，对象通常不能直接实时读取。需要用 &lt;code&gt;juicefs tier restore&lt;/code&gt; 命令先解冻文件，该命令会向对象存储服务发起恢复请求，对象能否读取以及何时可读，取决于云厂商的恢复机制；恢复完成后，业务再重新发起读取。&lt;/p&gt;
&lt;p&gt;因此，归档层更适合长期保存、极低频访问的数据，不适合仍需随时在线读取的业务路径。实际使用时，需要同时评估存储成本、恢复时间和恢复成本。&lt;/p&gt;
&lt;h2&gt;05 后续演进方向&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;降低归档类存储的操作成本&lt;/strong&gt;：归档类存储虽然具有较低的长期存储成本，但在写入、恢复、提前删除和生命周期转换等方面通常存在更复杂的成本模型。如果直接将数据写入归档类型，在频繁变更或批量迁移场景下，可能带来额外的操作成本。&lt;/p&gt;
&lt;p&gt;后续，JuiceFS 可结合对象存储的生命周期管理机制，先将数据写入标准存储类型，并在对象上附加相应的 Object Tag。用户随后可以通过云厂商的生命周期规则，根据标签自动、批量地将数据转换到低频或归档存储层。这样既能保留 JuiceFS 在文件系统层面的分层管理能力，也可以利用对象存储原生的批量转换机制，降低批量归档和层级转换过程中的额外开销。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;扩展到多桶、多云的分层管理&lt;/strong&gt;：当前分层存储主要基于同一对象存储后端内的不同 Storage Class。后续，JuiceFS 也可以进一步将“层级”概念扩展到不同存储桶、不同对象存储服务，甚至不同云之间，使分层管理不再局限于单一存储后端。&lt;/p&gt;
&lt;p&gt;例如，可以将热数据放置在以本地高性能 SSD 为后端的 MinIO 中，将冷数据或归档数据放置在云厂商的低成本归档存储桶中，并通过策略将数据从热层逐步迁移到冷层。通过这种方式，JuiceFS 有机会在统一文件系统命名空间下，实现跨桶、跨云、跨介质的数据分层管理。&lt;/p&gt;&lt;/div&gt;</description><pubDate>Fri, 22 May 2026 06:20:12 +0000</pubDate><guid>https://www.juicefs.com/zh-cn/blog/engineering/juicefs-v1-4-tiered-storage-design-reduce-cost</guid></item><item><title>AI 战略下架构演进：小米基于 JuiceFS 的统一存储实践</title><link>https://www.juicefs.com/zh-cn/blog/user-stories/xiaomi-unified-ai-storage-practice-juicefs</link><description>&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;小米存储团队自 2021 年起推进基于 JuiceFS 的文件存储平台建设，最初主要面向云原生及部分业务场景提供文件存储能力。2024 年，小米提出全面 AI 战略后，原有异构存储体系在选型接入、数据流转和研发运维等方面的问题进一步显现。基于多协议接入、弹性扩展、多云适配和高性能访问等能力，团队最终确立了以 JuiceFS 为核心建设统一文件存储基座的方向，用于统一支撑大数据、云原生和 AI 等业务场景。&lt;/p&gt;
&lt;p&gt;围绕这一目标，平台进一步建设了容量层、性能层和缓存层等核心能力，在降低多系统接入和数据流转复杂度的同时，兼顾大规模存储与高性能访问需求。&lt;strong&gt;过去两年，随着生成式 AI 和智能驾驶等业务快速发展，该平台已支撑大模型、智驾训练、推理加速和大数据上云等典型场景。目前，平台已具备支撑千亿级文件数量和 EB 级存储规模的能力，并可覆盖从原始数据、训练数据到模型文件分发的 AI 存储链路&lt;/strong&gt;。&lt;/p&gt;
&lt;h2&gt;01 AI 战略下存储架构挑战&lt;/h2&gt;
&lt;p&gt;2023 年之前，小米与大多数公司类似，在不同业务场景中分别建设了多套存储系统。其中，大数据领域主要基于 HDFS 构建数据平台；AI 相关业务由于当时大模型尚未大规模兴起，主要依赖云上的 PFS/NAS 等高性能文件存储服务。&lt;/p&gt;
&lt;p&gt;在此期间，我们也开始引入 JuiceFS，并配套建设内部自研 FDS（File Storage Service），通过 CSI Driver 等组件为云原生及部分业务场景提供文件存储能力。
随着业务需求持续演进，这些存储系统在各自场景中独立迭代、独立维护，逐渐形成了较为复杂的异构存储格局。&lt;/p&gt;
&lt;p&gt;2024 年，小米正式提出全面 AI 战略。原有存储架构在选型、接入、数据流转和研发运维等方面的短板开始集中显现，主要体现在以下几个方面：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;选型与接入成本高&lt;/strong&gt;：存储系统类型多、能力边界不一，业务团队需要分别理解和适配，使用门槛较高；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据流转效率低&lt;/strong&gt;：系统间缺乏统一访问方式，跨系统数据拷贝频繁，影响研发效率；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;研发运维力量分散&lt;/strong&gt;：多套系统独立维护和演进，资源难以聚焦到 AI 战略所需的核心基础设施建设中。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;针对这些问题，我们在 2024 年进行了深入的内部讨论和架构调整，开始重新梳理面向 AI、大数据和云原生场景的统一存储架构。&lt;/p&gt;
&lt;h2&gt;02 基于 JuiceFS 建设统一文件基座&lt;/h2&gt;
&lt;h3&gt;选型思考：多协议支持、弹性、多云、高性能&lt;/h3&gt;
&lt;p&gt;JuiceFS 是一款天然支持多协议、具备弹性扩展能力、提供高性能读写的分布式文件系统，能够完整适配原生 AI 场景与大数据场景的存储需求。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;1JuiceFS 架构图.drawio&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;JuiceFS 社区版架构图&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;在云原生领域，我们自 2021 年起已开始引入 JuiceFS，并持续进行内部自研与迭代优化。同时，我们也与 JuiceFS 开源社区保持了紧密的合作关系，共同推动技术演进与场景落地。&lt;/p&gt;
&lt;p&gt;在 AI 场景中，模型训练与推理大量依赖 POSIX 语义，这与 JuiceFS 的能力天然契合。与此同时，在大数据领域，我们原本就在推进大数据上云过程中的 HDFS 替代工作，业内已有诸多成熟实践，基于 HDFS 协议进行适配改造同样具备可行性。&lt;/p&gt;
&lt;p&gt;综合多协议支持、弹性扩展、多云适配和高性能读写等因素，我们最终选择以 JuiceFS 作为统一文件存储基座的核心组件，解决此前多平台、多业务使用不同文件系统带来的数据流转复杂、接入成本高和运维分散等问题。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;小米存储架构演进&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;基于 JuiceFS 的统一文件存储基座架构演进&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;h3&gt;存储层能力建设&lt;/h3&gt;
&lt;p&gt;我们的核心目标，是基于 JuiceFS 构建统一的文件存储层，对外提供大容量、高性能的存储能力和标准化接入接口，统一支撑大数据、云原生和 AI 三类核心业务场景。&lt;/p&gt;
&lt;p&gt;在客户端层面，我们充分利用 JuiceFS 的多协议能力，提供 POSIX、Hadoop SDK、Python SDK、S3 网关等多种接入方式，目前这些方式已经在内部业务中得到实际应用。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;存储基座技术架构&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;JuiceFS 统一文件存储基座技术架构&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;在数据面，整体架构主要分为容量层、性能层和缓存层：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;容量层：以公有云对象存储为基础，面向 EB 级存储规模建设，支持多云部署，可覆盖不同战略机房和多家云厂商环境。&lt;/li&gt;
&lt;li&gt;性能层：基于 Ceph 和全闪机器进行大规模调优，用于承载 AI 训练等对吞吐和时延要求较高的场景。&lt;/li&gt;
&lt;li&gt;缓存层：针对 AI 训练数据集“一次写入、多次读取、极少修改”的特点，基于 NVMe 和 RDMA 自研高性能分布式缓存系统，用于降低重复读取成本并提升训练数据访问效率。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在控制面，我们对社区版能力进行了定制化改造。元数据方面，自研了基于 Raft 协议的分布式元数据服务，以满足内部基建系统打通和多系统接入需求，并提升系统可靠性与扩展性；后台管理方面，建设了统一管理服务，负责数据生命周期管理、分层存储、垃圾回收，以及热数据从容量层向性能层或缓存层的预热等能力。&lt;/p&gt;
&lt;p&gt;通过上述建设，JuiceFS 在小米内部逐步成为统一文件存储基座，既能支撑大规模容量型存储，也能满足 AI 训练场景下的高性能访问需求。目前，相关架构已经在线上生产环境运行，并支撑了大模型训练所需的高吞吐访问能力。&lt;/p&gt;
&lt;h2&gt;03 业务实践&lt;/h2&gt;
&lt;p&gt;在统一文件存储基座建设过程中，JuiceFS 已逐步覆盖小米内部的大数据、云原生和 AI 等核心业务场景。&lt;strong&gt;从整体规模看，该方案能够支撑 EB 级存储规模和千亿级文件数量；从能力建设看，则通过容量层、性能层和缓存层的协同设计，兼顾大规模存储与高性能访问需求&lt;/strong&gt;。下面将结合大数据上云和 AI 存储链路两个典型场景，介绍 JuiceFS 在小米内部的具体实践。&lt;/p&gt;
&lt;h3&gt;场景 1： 大数据上云与湖仓存储统一&lt;/h3&gt;
&lt;p&gt;早期，小米大数据体系主要基于 Hadoop 生态建设，其中 HDFS 采用的是上一代存算耦合架构。在实际运行过程中，这一架构逐渐暴露出性能波动、运维复杂、综合成本偏高等问题。相比之下，云存储在弹性扩展、资源利用和成本控制方面具有更明显的优势。因此，自 2021 年起，小米开始系统推进大数据上云。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;大数据上云&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;大数据上云&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;h4&gt;上云路径：从冷数据到湖仓层&lt;/h4&gt;
&lt;p&gt;小米大数据上云整体经历了三个阶段。&lt;/p&gt;
&lt;p&gt;第一阶段是&lt;strong&gt;冷数据上云&lt;/strong&gt;。我们首先将 HDFS 中的冷数据迁移至云存储，这一过程持续了两年多。&lt;/p&gt;
&lt;p&gt;第二阶段是&lt;strong&gt;湖仓层上云&lt;/strong&gt;。在这一阶段，我们自研了统一的湖仓层文件系统，推动大数据存储架构从存算耦合向存算分离演进。&lt;/p&gt;
&lt;p&gt;第三阶段是&lt;strong&gt;基于 JuiceFS 建设统一存储基座&lt;/strong&gt;。在完成 JuiceFS 技术选型后，我们将湖仓层整体迁移至 JuiceFS。湖仓建设本身可以利用 Iceberg 社区原生支持的对象存储接入能力，例如 OSS、S3 等协议。但小米业务覆盖国内外多个区域，并同时使用多家云服务，如果逐一适配不同云厂商，接入和维护成本都会较高。&lt;/p&gt;
&lt;p&gt;因此，我们最终选择通过 JuiceFS 统一接入不同云存储。上层服务只需通过 SDK 切换后端存储地址，即可完成不同云环境下的访问适配，从而大幅降低多云接入复杂度。&lt;/p&gt;
&lt;p&gt;在数据迁移方面，小米自研的数据工厂平台支持将表的底层存储透明切换至新架构，并在后台逐步完成原有数据向云上的迁移，整个过程对业务方基本无感知。同时，JuiceFS 支持多云和本地化部署。如果未来出于成本或战略考虑需要切换至自建存储，也可以通过 JuiceFS 将数据平滑迁回，为业务保留更高的架构灵活性。&lt;/p&gt;
&lt;h4&gt;热表缓存加速，计算提效&lt;/h4&gt;
&lt;p&gt;数据上云后，我们进一步分析了湖仓层的数据访问模式。对于日常报表和分析任务，计算通常集中在天级或周级的热数据上，并不需要频繁扫描全量数据。因此，湖仓层的性能优化重点并不是简单提升全量读取能力，而是提升热数据的访问效率和任务执行稳定性。&lt;/p&gt;
&lt;p&gt;基于这一特点，我们与湖仓层协同建设了热表预热能力。系统会根据每日访问统计识别热点表及其热分区，并在任务执行前通过预热接口将相关数据提前加载至缓存层。对于每天早上 8 点前需要完成的周期性报表任务，热数据可以在计算开始前完成缓存预热，从而减少任务执行过程中的远端读取和重复访问。&lt;/p&gt;
&lt;p&gt;经线下和线上测试，热表缓存后，相关计算效率提升约 10%–20%，计算耗时和计算资源消耗均有所下降。目前，缓存规模已达到 PB 级，平均吞吐量约为 200 GB/s。缓存层的引入也降低了跨云专线压力和云存储 API 调用成本：通过提高热数据命中率，可以减少重复跨云读取，从而降低带宽消耗和访问费用。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;热表预热架构&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;热表预热架构&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;h4&gt;大数据应用收益&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;性能方面&lt;/strong&gt;：切换至 JuiceFS 后，顺序读写性能明显提升，部分场景下提升超过 1 倍。相关计算任务上线后，整体任务耗时降低约 10%–30%。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;成本方面&lt;/strong&gt;：从小米内部成本口径看，统一存储架构显著降低了存储成本。其中，国内场景存储成本降低约 70%，海外场景降低约 90%。海外原方案主要基于云主机和 EBS 构建 HDFS 三副本，副本率较高，导致整体存储成本偏高。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;稳定性与运维方面&lt;/strong&gt;：在原有混部架构下，大量计算任务运行时容易挤占节点资源，导致节点负载升高，并进一步影响存储性能。采用存算分离架构后，计算任务运行在独立计算节点上，任务耗时更加稳定，后续扩容和规模化管理也更加灵活。&lt;/p&gt;
&lt;h3&gt;场景 2： AI 一站式存储&lt;/h3&gt;
&lt;p&gt;AI 存储分为三个阶段：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;原始数据阶段&lt;/strong&gt;：需存储大量原始数据，经处理（如 ETL 处理）后用于训练，产出训练数据集，再投入高性能训练环境供训练任务运行。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;训练阶段&lt;/strong&gt;：训练任务需要高吞吐、低延迟的数据访问能力，以降低 IO 等待时间并提升 GPU 利用率；训练完成后产出模型文件，用于后续推理任务。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;推理阶段&lt;/strong&gt;：模型文件需快速分发至具体节点，以便推理任务启动时快速拉取。&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;AI存储流程&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;AI 存储流程&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;此前，数据在多个系统间流转，业务方与自身均感受不便。统一采用 JuiceFS 后，可基于不同类型满足多样化深度需求。&lt;/p&gt;
&lt;h4&gt;各阶段需求与方案对比&lt;/h4&gt;
&lt;p&gt;AI 一站式存储需要覆盖原始数据、训练数据和模型文件三个阶段，不同阶段对容量、性能、成本和分发效率的要求各不相同。下表对各阶段的业务需求、此前方案和当前方案进行了对比。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-table block-table"&gt;

&lt;table&gt;
    
        &lt;caption&gt;方案比对&lt;/caption&gt;
    
    
        &lt;thead&gt;
            &lt;tr&gt;
                
                    
                        
                        
                            &lt;th scope="col"  &gt;
                                
                                    
                                        使用场景
                                    
                                
                            &lt;/th&gt;
                        
                    
                
                    
                        
                        
                            &lt;th scope="col"  &gt;
                                
                                    
                                        业务需求
                                    
                                
                            &lt;/th&gt;
                        
                    
                
                    
                        
                        
                            &lt;th scope="col"  &gt;
                                
                                    
                                        前期方案
                                    
                                
                            &lt;/th&gt;
                        
                    
                
                    
                        
                        
                            &lt;th scope="col"  &gt;
                                
                                    
                                        当前方案
                                    
                                
                            &lt;/th&gt;
                        
                    
                
            &lt;/tr&gt;
        &lt;/thead&gt;
    
    &lt;tbody&gt;
        
            
                &lt;tr&gt;
                    
                        
                            
                            
                                
                                    &lt;th scope="row"  &gt;
                                        
                                            
                                                原始数据
                                            
                                        
                                    &lt;/th&gt;
                                
                            
                        
                    
                        
                            
                            
                                
                                    &lt;td  &gt;
                                        
                                            
                                                • 大容量、低成本存储&lt;br&gt;• 支持高并发数据处理&lt;br&gt;• 适配百 PB 级及以上数据规模
                                            
                                        
                                    &lt;/td&gt;
                                
                            
                        
                    
                        
                            
                            
                                
                                    &lt;td  &gt;
                                        
                                            
                                                • 直接使用对象存储&lt;br&gt;• HDFS&lt;br&gt;• 其他低成本存储系统
                                            
                                        
                                    &lt;/td&gt;
                                
                            
                        
                    
                        
                            
                            
                                
                                    &lt;td  &gt;
                                        
                                            
                                                JuiceFS 容量型存储&lt;br&gt;• 底层依托多云对象存储，屏蔽云厂商差异&lt;br&gt;• 支撑 EB 级容量和千亿级文件规模&lt;br&gt;• 支持百万级并发任务处理
                                            
                                        
                                    &lt;/td&gt;
                                
                            
                        
                    
                &lt;/tr&gt;
            
        
            
                &lt;tr&gt;
                    
                        
                            
                            
                                
                                    &lt;th scope="row"  &gt;
                                        
                                            
                                                训练数据
                                            
                                        
                                    &lt;/th&gt;
                                
                            
                        
                    
                        
                            
                            
                                
                                    &lt;td  &gt;
                                        
                                            
                                                • 高吞吐、低延迟访问&lt;br&gt;• 降低 IO 同步等待时间&lt;br&gt;• 提升 GPU 利用率
                                            
                                        
                                    &lt;/td&gt;
                                
                            
                        
                    
                        
                            
                            
                                
                                    &lt;td  &gt;
                                        
                                            
                                                • PFS、NAS 等高性能文件存储&lt;br&gt;• 性能较好，但系统成本较高
                                            
                                        
                                    &lt;/td&gt;
                                
                            
                        
                    
                        
                            
                            
                                
                                    &lt;td  &gt;
                                        
                                            
                                                JuiceFS 性能型 / 缓存型存储&lt;br&gt;• 支持 TB/s 级吞吐和低延迟访问&lt;br&gt;• 结合异步 checkpoint 机制，降低 IO 同步耗时&lt;br&gt;• 通过缓存加速提升训练数据访问效率
                                            
                                        
                                    &lt;/td&gt;
                                
                            
                        
                    
                &lt;/tr&gt;
            
        
            
                &lt;tr&gt;
                    
                        
                            
                            
                                
                                    &lt;th scope="row"  &gt;
                                        
                                            
                                                模型文件
                                            
                                        
                                    &lt;/th&gt;
                                
                            
                        
                    
                        
                            
                            
                                
                                    &lt;td  &gt;
                                        
                                            
                                                • 模型文件快速分发&lt;br&gt;• 支持高效拉取和加载&lt;br&gt;• 保障推理服务快速启动
                                            
                                        
                                    &lt;/td&gt;
                                
                            
                        
                    
                        
                            
                            
                                
                                    &lt;td  &gt;
                                        
                                            
                                                • P2P 分发&lt;br&gt;• 工作流分发&lt;br&gt;• PFS 等高性能文件存储
                                            
                                        
                                    &lt;/td&gt;
                                
                            
                        
                    
                        
                            
                            
                                
                                    &lt;td  &gt;
                                        
                                            
                                                JuiceFS 缓存加速分发&lt;br&gt;• 利用缓存机制提升模型加载效率&lt;br&gt;• 单机顺序加载性能最高可达 16 GB/s&lt;br&gt;• 相比本地盘、FDS 等方案，加载耗时可降低数倍
                                            
                                        
                                    &lt;/td&gt;
                                
                            
                        
                    
                &lt;/tr&gt;
            
        
    &lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;h4&gt;高性能缓存加速，提效降本&lt;/h4&gt;
&lt;p&gt;在 AI 训练场景中，训练数据集通常具有“一次写入、多次读取、极少修改”的特点，属于典型的读多写少访问模式，适合通过缓存提升数据访问效率。&lt;/p&gt;
&lt;p&gt;以内部智驾训练场景为例，数据集在成熟后，一个版本周期内数据量可能继续增长，但已有数据通常很少修改。此前采用的高性能文件存储虽然能够满足训练性能要求，但对于这类以重复读取为主的数据访问模式而言，存在一定的性能冗余和成本浪费。因此，我们开始推进基于 JuiceFS 的高性能缓存加速方案。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;训练流程&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;智驾场景训练流程&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;缓存方案具备多方面优势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;IO 路径短&lt;/strong&gt;：客户端直接操作文件，IO 路径大幅缩短，响应迅速。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;性能优化&lt;/strong&gt;：通过 RDMA 和零拷贝优化，性能显著提升。与之前的高性能存储相比，吞吐量提升 20%以上，且仍在持续优化。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;成本降低&lt;/strong&gt;：原基于 PFS 的存储采用副本机制，虽部分场景使用 EC 编码，但副本因稳定性更高而应用更普遍。采用缓存方案后，可实现单副本存储，成本降低 60%以上。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;资源整合利用&lt;/strong&gt;：在支持 CPU 训练时，GPU 机器通常挂载有 NVMe 盘，单机约有 10TB 左右空间。此前这些资源在业务场景中分散使用，利用率不高。现在，我们将分散的 NVMe 资源统一纳入缓存池，为就近的 GPU 训练和数据处理任务提供加速能力。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;04 未来规划&lt;/h2&gt;
&lt;p&gt;面向未来，我们将重点围绕以下三个方向持续演进。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;首先，持续提升统一文件存储基座的稳定性、性能和扩展性&lt;/strong&gt;。随着 AI 业务快速发展，训练、推理和数据处理任务对存储系统的吞吐、时延和可靠性提出了更高要求。后续我们将继续优化底层架构和关键链路，提升系统在大规模并发访问场景下的服务能力。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;其次，加强海量数据的生命周期管理&lt;/strong&gt;。当前业务数据规模持续增长，但不同类型数据在存储层级、访问频率和保留周期上的管理仍有进一步优化空间。我们将结合数据冷热特征、业务访问模式和成本模型，优化分层存储、数据归档、预热和清理策略，降低单位存储成本，提升整体资源利用率。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;最后，持续完善数据管理与分析能力&lt;/strong&gt;。在统一文件存储基座之上，我们将进一步建设面向业务的数据管理能力，帮助用户更清晰地理解数据分布、访问行为和资源使用情况，为后续的数据治理、成本优化和业务决策提供支撑。&lt;/p&gt;
&lt;p&gt;以上是小米在统一文件存储基座建设中的阶段性实践。我们也期待与业界同行持续交流，共同探索更多技术实践。&lt;/p&gt;&lt;/div&gt;</description><pubDate>Tue, 12 May 2026 08:08:00 +0000</pubDate><guid>https://www.juicefs.com/zh-cn/blog/user-stories/xiaomi-unified-ai-storage-practice-juicefs</guid></item><item><title>分布式架构下配额设计：JuiceFS 的实现与典型案例</title><link>https://www.juicefs.com/zh-cn/blog/engineering/juicefs-distributed-quota-design-and-case-studies</link><description>&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;在分布式存储环境中，存储资源通常由多个用户、项目和业务共享使用。如果缺乏有效的约束机制，单一主体的异常写入或误操作，可能迅速消耗大量空间或 inode，进而影响系统稳定性与成本控制。配额管理正是为共享环境建立可预测资源边界的重要手段。&lt;/p&gt;
&lt;p&gt;但在分布式系统中，配额管理并不只是“设置上限”这么简单。系统需要在多客户端并发写入、元数据异步更新和整体吞吐之间取得平衡；同时，配额规则也需要落实到不同层级的管控对象上。为此，JuiceFS 提供了覆盖全局、目录以及用户维度的多层级配额能力，以支持从整体容量控制到个体与团队约束的不同场景。&lt;/p&gt;
&lt;p&gt;本文将介绍这套配额机制的设计与实现，包括核心数据结构、同步模型，以及写入与删除流程中的校验与统计更新逻辑；同时，也会结合典型案例，说明配额统计、空间释放和超限写入等场景中的常见现象。&lt;/p&gt;
&lt;h2&gt;01 JuiceFS 支持的配额类型与资源维度&lt;/h2&gt;
&lt;p&gt;JuiceFS 配额支持两类资源维度：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Space：表示已使用的存储空间。这里的统计采用文件系统侧的占用口径，并按块粒度进行对齐计算；后文“写入链路”部分将进一步解释 4 KiB 对齐下的增量估算方式。  &lt;/li&gt;
&lt;li&gt;Inodes：表示已使用的 inode 数量。在大量小文件场景下，inode 往往比 space 更早成为约束瓶颈，因此也必须纳入配额治理范围。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;围绕这两类资源，JuiceFS 当前支持四种配额类型。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: left;"&gt;配额类型&lt;/th&gt;
&lt;th style="text-align: left;"&gt;作用范围&lt;/th&gt;
&lt;th style="text-align: left;"&gt;主要解决问题&lt;/th&gt;
&lt;th style="text-align: left;"&gt;典型使用场景&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;文件系统总配额&lt;/td&gt;
&lt;td style="text-align: left;"&gt;整个文件系统&lt;/td&gt;
&lt;td style="text-align: left;"&gt;防止整体资源失控&lt;/td&gt;
&lt;td style="text-align: left;"&gt;成本预算控制、容量上限&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;子目录配额&lt;/td&gt;
&lt;td style="text-align: left;"&gt;目录子树&lt;/td&gt;
&lt;td style="text-align: left;"&gt;阻断异常写入行为&lt;/td&gt;
&lt;td style="text-align: left;"&gt;防止误操作、小文件风暴&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;用户配额&lt;/td&gt;
&lt;td style="text-align: left;"&gt;单个用户&lt;/td&gt;
&lt;td style="text-align: left;"&gt;不同业务互不影响&lt;/td&gt;
&lt;td style="text-align: left;"&gt;多租户数据管理&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;用户组配额&lt;/td&gt;
&lt;td style="text-align: left;"&gt;项目或部门&lt;/td&gt;
&lt;td style="text-align: left;"&gt;成本分摊与团队限制&lt;/td&gt;
&lt;td style="text-align: left;"&gt;AI 项目共享环境&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;其中，用户配额和用户组配额预计将在社区版 1.4 中发布。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;在实际使用中，一个常见、有效的组合策略是：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;文件系统总配额做兜底；  &lt;/li&gt;
&lt;li&gt;目录配额专治“个体滥用”和“小文件风暴；  &lt;/li&gt;
&lt;li&gt;用户/组配额用于多租户管理。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这种分层限制既能控制整体资源上限，也能避免单个主体的异常增长影响其他业务。&lt;/p&gt;
&lt;h2&gt;02 配额实现机制&lt;/h2&gt;
&lt;h3&gt;同步模型与数据结构&lt;/h3&gt;
&lt;p&gt;配额实现的难点在于“如何在多客户端并发写入下，以可接受的代价完成检查、统计和收敛”。JuiceFS 的客户端分布在多个节点上，会持续发起创建、写入、截断、删除等资源变更操作；如果每次变更都要求后端执行强一致检查与更新，写入路径将承担难以接受的额外开销。&lt;/p&gt;
&lt;p&gt;因此，配额机制需要同时满足两个目标：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;性能：避免每次写入都触发一次后端强一致更新。  &lt;/li&gt;
&lt;li&gt;一致性：多客户端并发写入时，确保系统用量最终收敛，并尽可能在写入前阻止超限操作。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;基于这一权衡，JuiceFS 采用了“本地累计、周期 flush、定期 refresh”的同步模型&lt;/strong&gt;：客户端先在本地内存中累计资源增量，由后台任务定期批量持久化到元数据后端；同时，客户端再周期性从后端拉取最新配额配置和基准用量，逐步对齐各自的全局视图。客户端之间不直接通信，而是以元数据后端作为统一的状态汇聚点。换句话说，JuiceFS 的配额并不追求每次操作上的强一致，而是在周期同步下实现最终一致的资源管控。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;存储架构&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;在当前实现中，配额增量每 &lt;strong&gt;3 秒&lt;/strong&gt;持久化一次（&lt;code&gt;flushQuotas&lt;/code&gt;）；客户端约每 12 秒从后端重新加载一次最新的配额配置和基准用量（随挂载心跳触发的 &lt;code&gt;refresh&lt;/code&gt; 调用）。这意味着，在极端情况下，不同客户端之间看到的全局视图可能存在约 12 秒的偏差，但会在后续同步过程中逐步收敛一致。&lt;/p&gt;
&lt;p&gt;配额信息由 &lt;code&gt;Quota&lt;/code&gt; 结构体统一管理，它表征单个配额实体，可适配目录、用户、用户组等不同类型的管控对象。其核心设计是将基准用量与增量用量解耦：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UsedSpace / UsedInodes：表示“后端已持久化的基准用量”。  &lt;/li&gt;
&lt;li&gt;newSpace / newInodes：表示“本客户端本地累计的增量”，尚未 flush 到后端。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="codehilite"&gt;&lt;code class="language-go"&gt;type Quota struct {
    MaxSpace, MaxInodes   int64  // 最大空间和 inode 限制
    UsedSpace, UsedInodes int64  // 已使用的空间和 inode
    newSpace, newInodes   int64  // 待同步的新增使用量
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;在 inode 统计上，还需要特别考虑硬链接。不同配额类型对硬链接的计数语义并不相同。对于目录配额，统计按目录项进行：在某目录下创建一个硬链接，该目录的空间与 inode 用量各增加 1，删除时相应递减。对于用户配额和用户组配额，统计则按文件对象（inode）去重：同一文件即使存在多个硬链接，在 UID/GID 维度下也只计一次，因此创建或删除硬链接不会改变对应用户或用户组的用量。&lt;/p&gt;
&lt;h3&gt;配额存储&lt;/h3&gt;
&lt;p&gt;在配额存储机制方面，文件系统总配额作为全局“红线”，其容量与 Inode 上限直接持久化于元数据引擎中，由客户端在挂载时加载并执行硬限制拦截，确保底层资源不被穿透。&lt;/p&gt;
&lt;p&gt;相比之下，目录、用户和用户组配额的检查与增量累计更多依赖客户端侧完成。客户端在内存中维护以 inode、UID、GID 为键的索引结构，并周期性从后端同步对应的 &lt;code&gt;Quota&lt;/code&gt; 信息，从而在高频 I/O 场景下保持较低的查询开销。需要强调的是，客户端内存中的状态只是运行时缓存和增量视图，配额配置与基准用量的权威来源仍然是元数据后端。&lt;/p&gt;
&lt;h3&gt;配额检查&lt;/h3&gt;
&lt;p&gt;仅有同步模型和存储结构还不够，配额逻辑还必须嵌入具体的资源变更路径中。一次写入并不只是简单的数据追加，它可能同时伴随 inode 创建、块分配、目录项变化以及父级统计更新；在多客户端并发条件下，这些变化会共同作用于同一组配额约束。因此，只有把检查和统计更新真正放入写入、创建、截断、删除等操作路径，才能避免执行层面的超限写入和统计失真。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;22&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;写入文件： Quota 检查与更新流程图&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;h4&gt;写入前：增量估算与多维配额检查&lt;/h4&gt;
&lt;p&gt;当用户发起写入、创建或截断等可能改变资源用量的操作时，客户端首先估算该操作带来的资源增量，包括空间占用与 inode 变化。&lt;/p&gt;
&lt;p&gt;空间增量基于底层数据块的实际分配粒度（如 4 KiB 对齐）进行估算，因此需要进行块级对齐计算。inode 的增量主要发生在创建类操作中，例如新建文件或目录。&lt;/p&gt;
&lt;p&gt;在获得本次操作的资源增量后，客户端会在实际写入前执行配额校验。校验范围覆盖多个维度，包括用户与用户组配额、文件系统总配额以及所在目录树的目录配额。若任一维度在本次操作后可能超出限制，则请求会被拒绝，并返回配额超限或空间不足等错误。&lt;/p&gt;
&lt;p&gt;通过在写入路径前置校验，可以在资源变更发生前阻断风险，避免后续清理或回滚带来的复杂处理。&lt;/p&gt;
&lt;h4&gt;写入后：本地累计增量与后台批量同步&lt;/h4&gt;
&lt;p&gt;写入成功后，本次操作产生的资源增量将被纳入相应的用量统计，并按既定收敛机制与全局状态对齐。具体来说，三类统计都会受到影响：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;全局层面：文件系统整体用量会增加（或减少）；  &lt;/li&gt;
&lt;li&gt;目录层面：相关目录子树的用量也会随之变化；  &lt;/li&gt;
&lt;li&gt;用户/用户组层面：对应主体的用量同样需要累加。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些更新首先反映在客户端本地累计的增量中，而不会立即以强一致方式写回后端；随后再由后台任务批量 flush，并通过周期性的 refresh 与其他客户端逐步对齐，最终完成全局收敛。&lt;/p&gt;
&lt;h2&gt;03 用量统计（stats）：实现配额系统的基础&lt;/h2&gt;
&lt;p&gt;配额机制要发挥作用，前提是系统能够以较低开销掌握当前资源用量。无论是规模庞大的目录树，还是数量众多的用户与用户组，如果每次检查都依赖实时全量扫描，性能成本都会难以接受。因此，高效且可靠的用量统计机制，是配额系统得以落地的前提。&lt;/p&gt;
&lt;h3&gt;目录 stats&lt;/h3&gt;
&lt;p&gt;目录配额约束的是整个目录子树的空间与 inode 总量，而不是单个文件的大小，因此需要依赖目录级用量统计作为支撑。&lt;/p&gt;
&lt;p&gt;需要特别注意的是，目录统计（DirStats）与目录配额（Quota）的统计口径并不相同：目录统计仅计算当前目录下一级子目录和子文件的用量总和，属于单层统计；而目录配额统计的是整个目录子树的总用量，属于递归统计。这一设计使得目录统计能够以更低的开销维护，而目录配额则提供完整的子树用量视图。&lt;/p&gt;
&lt;p&gt;实现这类统计的关键，&lt;strong&gt;在于大规模目录树下保持低开销与高可用性。&lt;/strong&gt;JuiceFS 延续了与配额机制一致的思路：本地高频更新、后台批量持久化。客户端在内存中维护目录用量增量；当写入、删除等操作发生时，先在本地记录变化，再由后台任务定期批量同步到元数据后端。&lt;/p&gt;
&lt;p&gt;同时，系统不会在挂载时全量加载目录树统计。在目录规模较大时，全量加载会带来显著的耗时与内存开销。因此目录统计采用按需获取策略：仅在配额检查、用量汇总、运维查询等需要精确用量的场景下，才从后端加载对应目录的统计数据。&lt;/p&gt;
&lt;p&gt;当用户通过 &lt;code&gt;df&lt;/code&gt; 或应用通过 &lt;code&gt;statfs&lt;/code&gt; 获取用量信息时，JuiceFS 在性能与准确性之间做了折中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;优先使用本地缓存的已用空间和 inode 进行快速计算；  &lt;/li&gt;
&lt;li&gt;如果本地基准不完整（如刚启动）或需要更高实时性，再从后端拉取最新的全局计数进行校准；  &lt;/li&gt;
&lt;li&gt;最后叠加本地未同步的增量，以使结果更贴近当前节点的真实写入状态。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在得到已用量之后，客户端再结合是否配置了总容量上限来计算 &lt;code&gt;total&lt;/code&gt; 和 &lt;code&gt;avail&lt;/code&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;若已配置上限，总容量按该值，剩余可用容量为“上限减去已用”；  &lt;/li&gt;
&lt;li&gt;若未配置上限，则返回动态估算的总容量，确保 &lt;code&gt;df&lt;/code&gt; 等工具正常显示。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;另外，从根目录查询配额时，系统会展示最大空间和 inode 上限，便于管理员了解全局资源限制。&lt;/p&gt;
&lt;p&gt;此外，JuiceFS 将在 1.4 版本中支持对回收站（Trash）的目录统计进行实时更新。当文件被删除移入回收站或从回收站恢复、清理时，系统会即时更新回收站目录的统计信息，确保管理员能够准确掌握回收站的空间占用情况。&lt;/p&gt;
&lt;h3&gt;用户、用户组 stats&lt;/h3&gt;
&lt;p&gt;用户和用户组统计只会在对应的配额特性开启后才开始采集。开启前，内核路径中的 &lt;code&gt;updateUserGroupStat&lt;/code&gt; 调用会直接返回，不产生实际统计。开启后，客户端会在本地以内存 map 维护用量数据，以 uid 和 gid 作为 key，并在所有可能引起用量变化的路径上更新相应统计。&lt;/p&gt;
&lt;p&gt;需要特别注意的是，首次通过 &lt;code&gt;juicefs quota set --uid&lt;/code&gt; 或 &lt;code&gt;--gid&lt;/code&gt; 为某个用户或用户组设置配额时，系统会立即执行一次全局扫描，对已有文件进行全量遍历，以初始化存量统计数据。完成初始化后，后续的新增写入和删除操作则转为增量更新，无需再次执行全量扫描。&lt;/p&gt;
&lt;h2&gt;04 常见案例&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;1. 文件已删除，为什么文件系统总配额没有下降？对象存储账单为什么也没有变化？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这通常并不是统计错误，而是文件系统语义与统计模型共同作用的结果。&lt;/p&gt;
&lt;p&gt;例如，在 JuiceFS 中启用回收站后，删除操作并不会立即释放空间，而是先将文件移动到回收站以便后续恢复。因此，回收站中的文件仍会计入文件系统总配额和用户组配额，但不再计入原目录配额。&lt;/p&gt;
&lt;p&gt;另一个常见原因，是文件系统统计与对象存储侧计费之间本来就存在时间差。JuiceFS 的配额统计采用“本地累计 + 后台周期同步”的模型，短时间内不同客户端或不同统计接口之间可能尚未完全收敛；与此同时，对象存储侧也可能尚未完成垃圾回收（GC）或生命周期清理。因此，在短时间内看到文件系统用量、配额统计与对象存储账单不完全一致，通常属于预期现象，只要后续能够逐步收敛，一般不视为系统异常。&lt;/p&gt;
&lt;p&gt;此外，还需要注意，配额和 &lt;code&gt;statfs&lt;/code&gt; 展示的是文件系统视角下的空间占用与剩余容量，而对象存储账单则基于底层对象的实际存储模型，受分片、合并、延迟回收和生命周期规则等因素影响，两者本就不一定完全一致。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 配额已满，为什么追加写入已有文件时没有立即报错？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这通常与 JuiceFS 某些写入路径中的异步提交流程有关。对应用而言，&lt;code&gt;write&lt;/code&gt; 系统调用可能先成功返回，而实际的数据提交与相应的配额判定会在后续阶段完成。因此，从调用方视角看，追加写入似乎“成功”了，但最终数据未必真正持久化；如果后续提交阶段判定超出配额，对应写入仍可能失败。&lt;/p&gt;
&lt;p&gt;换句话说，应用看到 &lt;code&gt;write&lt;/code&gt; 返回成功，并不等价于这次写入已经完成最终提交。在涉及配额限制的场景中，更稳妥的做法是结合后续错误处理、关闭文件时的返回状态以及实际文件大小变化来判断写入是否真正生效。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. 配额还没用满，为什么创建文件却失败了？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这类现象通常与最终一致统计模型下的短暂视图偏差有关。&lt;/p&gt;
&lt;p&gt;例如，某个卷设置了 2000 个 inode 的总配额，系统中已经存在 1999 个文件，按理说还可以再创建 1 个文件。但在极端并发或刷新时序特殊的情况下，客户端本地缓存与后端基准计数之间可能出现短暂不一致，从而导致内存中的已用 inode 统计暂时偏大，最终提前拒绝了原本合法的创建请求。&lt;/p&gt;
&lt;p&gt;这类问题本质上来源于“本地累计 + 周期同步”的收敛模型：它避免了每次操作都依赖后端强一致更新的高开销，但也意味着在极端情况下，系统可能出现短时间的误判。通常这类误判会随着后续同步逐步消失，必要时也可以通过重试来缓解。&lt;/p&gt;
&lt;p&gt;这也说明，在分布式环境下，配额限制更适合被理解为一种高效且近实时的约束机制，而不是对每一次并发操作都做完全同步的强一致判断。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. 写入超出配额后，为什么“失败”的文件还留在目录里？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这并不是 JuiceFS 独有的行为，在遵循 POSIX 语义的文件系统中，这类现象并不罕见。&lt;/p&gt;
&lt;p&gt;例如，用户为某个目录设置了 1 GiB 配额，然后使用 &lt;code&gt;dd&lt;/code&gt; 尝试写入一个 2 GiB 文件。文件系统会先允许前 1 GiB 的合法写入；直到后续写入触发配额上限时，才返回 &lt;code&gt;Disk quota exceeded&lt;/code&gt;。因此，最终留下一个大小约为 1 GiB 的“未写完文件”，并不意味着系统行为异常，而是说明前半部分数据已经成功写入，后续部分才因超限而失败。&lt;/p&gt;
&lt;p&gt;文件系统负责报告错误，但不会替应用程序决定是否删除已经成功写入的数据。是否清理这种不完整文件，应由应用程序自行处理。这也是标准的 POSIX 语义：文件系统负责返回错误，应用程序负责后续清理与恢复。&lt;/p&gt;
&lt;h2&gt;05 小结&lt;/h2&gt;
&lt;p&gt;在分布式文件系统中，配额并不是一个简单的“计数器功能”，而是一套需要在性能、一致性与治理粒度之间权衡的系统设计。JuiceFS 通过写前校验、本地累计以及后台周期同步，在尽量降低写入路径开销的同时，使各类用量统计在最终一致模型下逐步收敛。基于这一机制，配额控制既覆盖文件系统全局容量，也支持目录、用户和用户组等多个层级，从而满足多租户隔离、个体约束和团队资源治理等典型场景的需求。&lt;/p&gt;
&lt;p&gt;如果在实际使用中遇到问题，或有不同的实践思路，欢迎在评论区分享与交流。&lt;/p&gt;&lt;/div&gt;</description><pubDate>Thu, 23 Apr 2026 04:48:05 +0000</pubDate><guid>https://www.juicefs.com/zh-cn/blog/engineering/juicefs-distributed-quota-design-and-case-studies</guid></item><item><title>浅析 Amazon S3 Files：工作机制、性能边界与 JuiceFS 对比</title><link>https://www.juicefs.com/zh-cn/blog/engineering/amazon-s3-files-vs-juicefs</link><description>&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;4 月 7 日，AWS 官方发布了一项新服务——Amazon S3 Files，允许用户无需搬迁数据，即可将 S3 存储桶作为高性能共享文件系统挂载到计算节点上。&lt;/p&gt;
&lt;p&gt;这不是业界第一次尝试让 S3 以文件系统方式被访问：从早期的 s3fs，到 AWS 后来推出的 Mountpoint for Amazon S3，再到今天的 S3 Files，S3 “像文件系统一样被访问”这条路，其实已经走了很多年。区别在于，前两者更多是在访问层做文章，而这一次，AWS 终于把共享访问、文件系统语义和托管高性能层真正捏成了一个原生方案。&lt;/p&gt;
&lt;p&gt;这也让 S3 Files 成为一个值得单独分析的新选项。对于希望以文件方式访问现有 S3 数据的业务来说，它提供了原生、轻量的方案；但放到 AI 模型训练、大数据分析等更复杂的场景中，它的实际表现究竟如何，仍需要结合其底层实现与运行机制来看。&lt;/p&gt;
&lt;p&gt;本文将围绕 S3 Files 的底层实现、性能边界以及与 JuiceFS 的差异展开分析。&lt;/p&gt;
&lt;h2&gt;01 S3 Files ：以 EFS 为高性能层的 S3 原生文件系统方案&lt;/h2&gt;
&lt;p&gt;从底层实现看，S3 Files 使用 Amazon EFS（Elastic File System）作为托管的高性能存储层，用来承接需要低延迟访问的数据和相关元数据，并在此基础上为 S3 提供完整的文件系统语义，包括一致性、文件锁和 POSIX 权限。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;可以把它理解为：AWS 在对象存储之上增加了一层基于 EFS 的文件系统访问面，使原本只能通过对象接口访问的数据，也能以目录、文件和挂载点的形式被计算节点直接使用；而文件系统与 S3 之间的数据变化，则由服务在后台自动同步。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;基于这种架构，S3 Files 并不会搬迁全量数据，而是只将当前工作集中的一部分数据按需放到高性能层中；而数据的“Source of Truth”依然保留在 S3 中。&lt;/p&gt;
&lt;h2&gt;02 S3 Files 如何工作：挂载、导入与同步机制&lt;/h2&gt;
&lt;p&gt;对 S3 Files 来说，挂载只是开始，真正影响体验的是挂载之后的数据路径：作用域如何确定，首次访问会导入什么，哪些请求会进入高性能层，写入后又会如何同步回 S3。这些机制，也直接决定了后文要讨论的性能边界与成本结构。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;S3 Files 挂载架构&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;S3 Files 挂载架构示意图&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;以 EC2 挂载现有 S3 bucket 为例，真正需要看清的不是挂载命令本身，而是挂载之后数据会如何被导入、访问与同步。下面是几个关键的技术细节与步骤。&lt;/p&gt;
&lt;h3&gt;a) 先确定作用域：导入全量 S3 桶，还是指定部分目录&lt;/h3&gt;
&lt;p&gt;两者皆可。 S3 Files 支持将整个 S3 存储桶作为文件系统挂载，也支持通过 Prefix（前缀） 限制作用域，&lt;/p&gt;
&lt;p&gt;例如只挂载 &lt;code&gt;s3://my-bucket/data/ml/&lt;/code&gt; 目录下。对于包含数千万个对象的庞大 S3 桶尤为重要，因为过大的作用域会增加元数据同步的负担。&lt;/p&gt;
&lt;p&gt;在计算节点上使用 S3 Files 时，AWS 提供了定制的挂载客户端 &lt;code&gt;amazon-efs-utils&lt;/code&gt;。挂载时使用的并不是存储桶名称，而是 AWS 为 S3 Files 分配的 file system ID。&lt;/p&gt;
&lt;p&gt;创建一个本地挂载目录，并使用专用的 &lt;code&gt;s3files&lt;/code&gt; 文件系统类型进行挂载：&lt;/p&gt;
&lt;pre class="codehilite"&gt;&lt;code class="language-plain"&gt;sudo yum -y install amazon-efs-utils
sudo mkdir /mnt/s3files
sudo mount -t s3files fs-1234567890abcdef0:/ /mnt/s3files
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;如果只希望访问某个子目录，也可以在挂载路径中进一步指定。但从实践上看，更推荐在创建 S3 Files 时就把作用域限定到明确的 prefix，而不是在一个过大的存储桶上再做后置控制。&lt;/p&gt;
&lt;h3&gt;b) 首次访问时会发生什么：导入触发方式与大小阈值&lt;/h3&gt;
&lt;p&gt;S3 Files 并不会在挂载后立即把整个数据集搬入高性能层。它的数据导入由访问事件触发，默认模式是 &lt;code&gt;ON_DIRECTORY_FIRST_ACCESS&lt;/code&gt;：当你第一次访问某个目录时，系统会导入该目录下文件的元数据，并将符合条件的小文件数据异步导入 EFS 高性能层。&lt;/p&gt;
&lt;p&gt;如果配置为 &lt;code&gt;ON_FILE_ACCESS&lt;/code&gt;，则首次遍历目录时只导入元数据，只有在文件第一次被实际读取时，数据才会进入高性能层。这种方式更节省空间和导入成本，但首读延迟也会更高。&lt;/p&gt;
&lt;p&gt;这里最关键的控制参数是 &lt;code&gt;sizeLessThan&lt;/code&gt;。默认情况下，只有小于 128 KB 的文件才会在导入时进入高性能层；更大的文件通常只导入元数据，内容仍然主要通过 S3 获取。&lt;strong&gt;换句话说，S3 Files 优先优化的是小文件和低延迟访问&lt;/strong&gt;，而不是把所有数据都预热到高性能层中。对于 AI 训练这类以 10 MB 级图片、音视频文件为主的数据集来说，这一点尤其关键：即使完成了目录遍历，这些大文件在默认配置下也未必会真正进入高性能层。&lt;/p&gt;
&lt;h3&gt;c) 同步周期与冲突解决机制&lt;/h3&gt;
&lt;p&gt;S3 Files 会在后台自动维护文件系统与 S3 之间的双向同步。S3 侧发生变化后，文件系统视图会随之更新；而在计算节点上的写入，则会先落到 EFS 高性能层，再由后台批量同步回 S3。默认情况下，系统会对修改进行一段时间的聚合，再执行回写。&lt;/p&gt;
&lt;p&gt;冲突处理的原则也很明确：&lt;strong&gt;S3 始终是 Source of Truth。&lt;/strong&gt; 如果文件系统侧的修改尚未同步回 S3，而对应对象已经在 S3 中被其他应用更新，系统会以 S3 中的最新版本为准，并将冲突文件移入 &lt;code&gt;.s3files-lost+found-*&lt;/code&gt; 目录。&lt;/p&gt;
&lt;h2&gt;03 S3 Files 的性能边界与成本结构&lt;/h2&gt;
&lt;p&gt;上一节解释的是 S3 Files 如何运行，这一节进一步讨论的，则是这种运行方式会带来怎样的性能边界与成本结构。高性能层占用、大文件读取路径、写入流转，以及局部更新和目录操作带来的放大效应，是实际选型中最需要重点考量的四个方面。&lt;/p&gt;
&lt;h3&gt;a) EFS 高性能层的占用、回收与成本&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;S3 Files 的高性能层并不是按容量上限做 LRU 淘汰，而是按访问时间进行生命周期管理。&lt;/strong&gt; 默认情况下，已同步到 S3 且 30 天未被读取的数据会从 EFS 高性能层中移除；这一时间由 &lt;code&gt;daysAfterLastAccess&lt;/code&gt; 控制，可配置范围为 1–365 天。&lt;/p&gt;
&lt;p&gt;这意味着，&lt;strong&gt;它的成本取决于有多少数据需要驻留在 EFS 中，以及驻留多久。&lt;/strong&gt; 如果工作集很大且长期保持活跃，相关费用就会持续上升。&lt;/p&gt;
&lt;h3&gt;b) 大文件直读与随机读：其实是客户端在“穿透”读取&lt;/h3&gt;
&lt;p&gt;S3 Files 对大文件的处理，并不是把所有读取都留在 EFS 高性能层中完成。默认情况下，&lt;code&gt;sizeLessThan&lt;/code&gt; 的值为 128 KB，它决定的是哪些文件会在导入时把数据放入高性能层；而对于已经同步到 S3 的数据，128 KB 及以上的读取会直接从 S3 流式返回。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;S3 Files 基于 128 KB 阈值的数据路由机制&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;S3 Files 基于 128 KB 阈值的数据路由机制&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;&lt;strong&gt;也就是说，S3 Files 的优化重点更偏向小文件和低延迟访问，而不是让大文件读取长期稳定命中高性能层。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这条直读路径依赖于计算资源本身具备读取源存储桶的权限。AWS 官方文档明确要求相关角色拥有 &lt;code&gt;s3:GetObject&lt;/code&gt; 和 &lt;code&gt;s3:GetObjectVersion&lt;/code&gt; 等权限；否则，客户端就无法直接从 S3 读取数据。&lt;/p&gt;
&lt;h3&gt;c) 顺序写的代价：大规模写入会引入额外流转成本&lt;/h3&gt;
&lt;p&gt;S3 Files 的写路径并不是直接落到 S3。&lt;strong&gt;所有写操作都会先进入 EFS 高性能层，再由后台同步回 S3。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这意味着，如果你的场景会持续产生大量结果数据，例如顺序写入数百 TB 的训练产物或分析结果，那么这些数据在流经 S3 Files 时，会额外引入两类成本：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据流转成本：写入先进入高性能层，随后再同步回 S3。相比直接写入 S3，这条路径会多出一层中间流转开销。  &lt;/li&gt;
&lt;li&gt;短期驻留成本：数据同步完成后，并不会立刻从高性能层中移除，而是要等到满足过期条件后才会清理。默认情况下，这意味着大批量写入产生的临时数据，可能在一段时间内持续占用 EFS 容量。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以某一区域当前价格为例，写入 EFS 约为 $0.06/GB，后台同步回 S3 的读取约为 $0.03/GB，仅数据流转这一层，每 1 TB 写入就大约会多出 $90 的附加成本。如果这些数据在同步完成后仍然继续驻留在 EFS 中，还会进一步产生对应的高性能层存储费用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;这也是为什么，S3 Files 更适合读取现有数据，而不适合长期承接大规模、持续性的结果写入。&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;d) 局部更新与目录操作：对象模型带来的放大效应&lt;/h3&gt;
&lt;p&gt;S3 Files 底层不对数据进行切块，而是尽量保持文件与 S3 对象之间的直接映射。&lt;strong&gt;这带来的代价是：一旦涉及大文件的局部随机写或追加写，应用层看起来只是一次很小的更新，底层同步回 S3 时却更容易放大为显著的对象写入与版本开销。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;例如，用户通过 S3 Files 在一个 &lt;strong&gt;100 GB&lt;/strong&gt; 的 &lt;code&gt;lmdb&lt;/code&gt; 文件中追加了一条 &lt;strong&gt;100 KB&lt;/strong&gt; 的图片 key，应用侧看到的只是一次很小的写入；但这类修改并不会立刻回写到 S3，而是会在&lt;strong&gt;大约 60 秒&lt;/strong&gt;内先做聚合，再同步回存储桶。&lt;strong&gt;它不会像块存储那样只改动一个离散块，而更可能放大为对象写入、同步时延和版本存储成本。&lt;/strong&gt; 文件越大、修改越频繁，这种代价就越值得警惕。&lt;/p&gt;
&lt;p&gt;目录重命名同样受 S3 扁平命名空间限制。S3 本身没有传统文件系统中的目录元数据，因此执行 &lt;code&gt;rename&lt;/code&gt; 或 &lt;code&gt;mv&lt;/code&gt; 时，S3 Files 不能只改一条元数据，而是必须在 S3 侧为目录中的每个文件写入新对象并删除旧对象。对于拥有千万级对象的目录，这会显著拉长同步时间，并增加 S3 请求成本；在同步完成前，文件系统视图与 S3 视图之间还可能暂时不完全一致。&lt;/p&gt;
&lt;p&gt;总体来看，S3 Files 的优势在于原生接入、零数据迁移，以及对现有 S3 资产的良好兼容。它的代价则在于：一旦场景转向大文件读取、持续写入、频繁局部更新或大目录操作，性能和成本都会更快被放大。也正因为如此，S3 Files 的优势更适合发挥在轻量共享访问场景中；而在训练、数据生产和大规模分析等重负载场景下，它的代价往往会更早暴露出来。&lt;/p&gt;
&lt;h2&gt;04 JuiceFS vs S3 Files：两种不同的架构思路&lt;/h2&gt;
&lt;p&gt;前一节已经看到，S3 Files 的很多边界并非偶然，而是这类方案的共性结果。无论是早期的 s3fs、主打高吞吐读取的 Mountpoint for Amazon S3，还是今天的 S3 Files，它们都尽量保持文件与 S3 对象之间的直接映射，以换取对现有 S3 数据的透明访问能力。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;这条路线的优势是透明和低改造，代价则是先天受制于 S3 的对象模型。&lt;/strong&gt; 这也是为什么目录操作更容易退化为对象级请求，大文件的局部更新也更容易演化为写放大、同步延迟和额外成本。&lt;/p&gt;
&lt;p&gt;也正因为如此，JuiceFS 与这类方案的差异，并不是某个功能点或单项指标的差别，而是两条架构路线的根本区别。&lt;strong&gt;JuiceFS 不是“把 S3 挂出来用”的访问层，而是构建在对象存储之上的云原生分布式文件系统。&lt;/strong&gt; 它采用数据与元数据解耦的架构：文件数据存放在底层对象存储中，元数据则由高性能键值数据库独立管理，因此更适合承接训练、分析和数据生产等更重的生产型负载。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;1JuiceFS 架构图.drawio&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;JuiceFS 社区版架构图&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;为了让大家能更直观地进行架构选型，我们从底层架构到高阶特性，将 JuiceFS 与 S3 Files 进行了全方位对比：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: left;"&gt;对比维度&lt;/th&gt;
&lt;th style="text-align: left;"&gt;JuiceFS&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Amazon S3 Files&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;整体架构&lt;/td&gt;
&lt;td style="text-align: left;"&gt;数据与元数据分离，文件切块后写入对象存储&lt;/td&gt;
&lt;td style="text-align: left;"&gt;基于 EFS 代理，数据不切块，1:1 动态根据设置的文件大小来映射对象（默认&amp;lt;128KB）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;核心成本&lt;/td&gt;
&lt;td style="text-align: left;"&gt;软件开源免费，主要成本来自对象存储、元数据引擎和缓存资源&lt;/td&gt;
&lt;td style="text-align: left;"&gt;除 S3 存储外，需额外支付 EFS 存储费($0.30/GB)及数据读写 Sync 费&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;读写放大(随机写)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;部分场景极低。数据切块后，局部随机写通常只更新受影响的数据块，无需重写全量数据&lt;/td&gt;
&lt;td style="text-align: left;"&gt;数据生产场景会很高，大文件随机修改会导致整个对象的重传重写&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;冷热分层策略&lt;/td&gt;
&lt;td style="text-align: left;"&gt;基于容量与访问热度，将热数据自动预热至计算节点的本地盘/内存缓存中&lt;/td&gt;
&lt;td style="text-align: left;"&gt;基于文件大小与访问时间。小文件(&amp;lt;128K)热数据缓存在 EFS，大文件绕过 EFS 直接读写 S3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;小文件性能&lt;/td&gt;
&lt;td style="text-align: left;"&gt;依赖全内存的独立元数据引擎(Redis/TiKV 等)，更适合大量小文件与元数据操作&lt;/td&gt;
&lt;td style="text-align: left;"&gt;依赖 EFS 性能与 NFS 协议&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;大文件吞吐&lt;/td&gt;
&lt;td style="text-align: left;"&gt;可结合本地 NVMe / 内存缓存提升吞吐&lt;/td&gt;
&lt;td style="text-align: left;"&gt;依赖 EFS 网关或 S3 直连性能，大规模并行吞吐与容量配额绑定&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;缓存一致性&lt;/td&gt;
&lt;td style="text-align: left;"&gt;强一致性 (Close-to-open)。由独立元数据服务统一仲裁&lt;/td&gt;
&lt;td style="text-align: left;"&gt;NFS Close-to-open。但遇到底层 S3 和文件系统并发修改冲突时，本地 EFS 数据会被丢弃至 lost+found，S3 强行作为 Truth&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;POSIX 兼容性&lt;/td&gt;
&lt;td style="text-align: left;"&gt;几乎 100% 兼容。 支持 Hard Links、原子级 Rename、各类锁语义&lt;/td&gt;
&lt;td style="text-align: left;"&gt;支持 NFSv4.1/4.2 子集。 不支持硬链接(Hard links)、不支持原子重命名&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;权限管理&lt;/td&gt;
&lt;td style="text-align: left;"&gt;支持标准 POSIX 权限、ACL、Extended ACL 等多种鉴权&lt;/td&gt;
&lt;td style="text-align: left;"&gt;支持标准 POSIX 权限、ACL、Extended ACL 等多种鉴权&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;加密与安全&lt;/td&gt;
&lt;td style="text-align: left;"&gt;传输加密、静态加密、并提供国密支持&lt;/td&gt;
&lt;td style="text-align: left;"&gt;传输级 TLS 加密、静态 SSE-KMS 密钥加密&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;AI 场景优化&lt;/td&gt;
&lt;td style="text-align: left;"&gt;深度优化了 LMDB、Safetensors 等 AI 常见格式的 mmap 读取与本地预热机制&lt;/td&gt;
&lt;td style="text-align: left;"&gt;无专门针对 AI 格式的底层优化，依赖基础文件流式读取&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;05 小结&lt;/h2&gt;
&lt;p&gt;没有绝对完美的银弹，只有最适合特定场景的方案。&lt;/p&gt;
&lt;p&gt;S3 Files 的面世，填补了 AWS 官方生态中“无缝、免搬迁将 S3 原生转换为文件系统”的空白。它的设计非常明显：&lt;strong&gt;S3 对象生态的 100% 格式透明，并针对性优化 AI 场景的小文件（&amp;lt;128KB）的读写性能。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;什么时候选择 S3 Files？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果核心诉求是在不改动现有架构的前提下，让旧应用、Shell 脚本或传统软件直接以文件方式访问现有 S3 数据；或者需要一个通用的共享文件空间，且以只读、小文件、顺序读写为主，那么 S3 Files 会是更自然的选择。它的原生托管、即插即用和零数据迁移能力，可以显著降低接入门槛（但是为了这个便利性可能需要付出高昂的 EFS 存储和同步成本来交换）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;什么时候选择 JuiceFS？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果业务面向 AI 模型训练、数据生产、高性能计算（HPC）或大数据分析，面临千万级小文件、TB 级大文件随机读写，或对 mmap、缓存命中率和整体吞吐有更高要求，那么 JuiceFS 会更适合。相比 S3 Files，JuiceFS 的数据切块、独立元数据引擎和更灵活的缓存体系，更适合承接重负载和长期运行的生产型和 AI 训推文件系统场景。&lt;/p&gt;&lt;/div&gt;</description><pubDate>Tue, 14 Apr 2026 08:29:00 +0000</pubDate><guid>https://www.juicefs.com/zh-cn/blog/engineering/amazon-s3-files-vs-juicefs</guid></item><item><title>一文解锁 JuiceFS 在 AI 场景中的性能优化</title><link>https://www.juicefs.com/zh-cn/blog/engineering/juicefs-ai-workload-performance-optimization</link><description>&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;大模型训练的算力规模持续扩张，GPU 算力不断提升的同时，数据访问瓶颈对系统整体性能的影响愈发突出。本地存储性能优异但扩展性有限，对象存储在成本与扩展性上具备优势，却在海量小文件、高并发场景下面临吞吐不足的问题，团队往往需要在二者之间艰难取舍。&lt;/p&gt;
&lt;p&gt;为此，分布式文件系统成为平衡高性能与可扩展性的关键方案。JuiceFS 已在多行业 AI 场景中广泛落地，其分布式架构能够在大规模数据访问场景下，同时兼顾高性能、强扩展与低成本。&lt;strong&gt;本文将从性能角度介绍 JuiceFS 的架构设计，分析不同访问模式下的核心性能瓶颈与优化方法。文中关键知识点均附对应详情链接，为用户理解 JuiceFS 性能机理、掌握常见调优方向提供参考。&lt;/strong&gt;&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;JuiceFS 在 AI 场景中的应用&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;JuiceFS 在 AI 场景中的应用&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;h2&gt;01 从架构看 JuiceFS 的性能基础&lt;/h2&gt;
&lt;p&gt;JuiceFS 分为社区版与企业版，二者整体架构一致，均采用元数据与数据分离的存储架构。客户端采用富客户端设计，承载包括部分元数据处理在内的多项核心逻辑，并同时提供元数据缓存与数据缓存能力，各模块协同工作以实现数据的高效定位与访问。底层数据存储基于对象存储构建，并可借助本地缓存进一步提升访问性能。对外接口上，JuiceFS 支持多种接入方式，其中 FUSE 最为常用，同时也兼容各类 SDK 与 S3 网关。&lt;/p&gt;
&lt;p&gt;社区版定位为通用文件系统，用户可根据需求选择不同的元数据引擎。小规模部署可选择 Redis，实现轻量、高响应的数据管理；大规模文件场景可选择 TiKV，以获得良好的横向扩展能力。（&lt;a href="https://juicefs.com/zh-cn/blog/solutions/juicefs-metadata-engine-selection-guide"&gt;参考：JuiceFS 元数据引擎选型指南&lt;/a&gt;）&lt;/p&gt;
&lt;p&gt;企业版面向复杂高性能场景，相较于社区版，最大的差异有两方面：企业版采用自研多分区元数据引擎，基于 Raft 构建纯内存集群，延迟低且横向扩展能力强，可支持 5,000 亿文件规模。相比社区版需多次 KV 请求完成的操作，企业版通常仅需一次或两次，并可在元数据集群内部处理复杂逻辑。其次，企业版支持分布式缓存共享：同组客户端可在同一区域内互访本地缓存，基于一致性哈希实现，提高缓存命中率和访问效率。在多节点高并发场景下，缓存空间可横向扩展，任务执行前可预热大部分所需数据，从而加速 AI 训练与推理，提高系统性能和稳定性。（&lt;a href="https://juicefs.com/zh-cn/blog/release-notes/juicefs-enterprise-5-3-500b-files-rdma-support"&gt;JuiceFS 企业版 5.3 特性详解：单文件系统支持超 5,000 亿文件，首次引入 RDMA&lt;/a&gt;）&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;JuiceFS 社区版和企业版架构&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;JuiceFS 社区版和企业版架构&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;h3&gt;数据分块设计&lt;/h3&gt;
&lt;p&gt;JuiceFS 将数据切块后存储于对象存储，这一设计是其提升性能的关键，将影响数据读取效率、缓存命中率及高并发访问下的吞吐能力。&lt;/p&gt;
&lt;p&gt;JuiceFS 会将文件拆分为多个 chunk。在每个 chunk 内部，系统维护管理结构 slice，用于跟踪数据写入和更新。当文件发生写入时，新数据不会覆盖已有 slice，而是以新的 slice 追加到 chunk 上层。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;chunk&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;理想情况下，每个 chunk 最终只应包含一个 slice。每个 slice 由若干 4 MB 的 block 组成，这些 block 是最终存储到对象存储的最小单元。默认情况下，缓存系统也以 block 为单位进行管理。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;block&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;从右上方示意图可以看出，文件更新采用追加式写入：红色部分为已有 slice，新数据以新的 slice 叠加。读取时，系统组合各层 slice 形成当前视图；碎片过多时，再通过 compaction 合并，以优化访问性能。更多关于数据分块的细节可参考&lt;a href="https://juicefs.com/docs/zh/community/architecture#how-juicefs-store-files"&gt;文档&lt;/a&gt;。&lt;/p&gt;
&lt;h3&gt;缓存体系&lt;/h3&gt;
&lt;p&gt;相较于直接访问对象存储，JuiceFS 的性能提升在很大程度上得益于其缓存体系。JuiceFS 客户端配备了高性能的本地缓存模块，与之相关的配置项如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cache-dir&lt;/code&gt;：用于指定缓存目录；  &lt;/li&gt;
&lt;li&gt;&lt;code&gt;cache-size&lt;/code&gt;：用于设定用于缓存的空间大小；  &lt;/li&gt;
&lt;li&gt;&lt;code&gt;prefetch&lt;/code&gt;：这是缓存模块中的一个参数，负责预取功能。当某一请求命中某个 block 时，会启动一个后台线程，将整个块完整拉取下来；  &lt;/li&gt;
&lt;li&gt;&lt;code&gt;write back&lt;/code&gt; 相关配置：用于提高写 IOPS，将需要上传至对象存储的数据块，先写入本地缓存，再异步上传至对象存储。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;企业版还具备一些进阶配置，例如通过 cache group 指定一批客户端，将它们的本地缓存配置为同一个分布式缓存组，实现缓存数据的共享。此外，no sharing 是与缓存组相关的配置，启用 no sharing 后，客户端仅从指定的缓存组读取数据，但不作为缓存组成员提供数据读取服务。如此一来，便形成了两级缓存：第一级是本地缓存，第二级是缓存组中其他节点上的缓存。&lt;/p&gt;
&lt;p&gt;另一个提升性能的机制是内存 buffer（读 buffer），具有以下作用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;合并 IO 请求&lt;/strong&gt;：可内存层面合并多个连续的 IO 请求。例如，系统发出三个 IO 请求，经内存缓存处理后，实际发出的可能仅有一个；  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自适应预读功能&lt;/strong&gt;：在大文件顺序读取场景下，自适应预读功能通过预读来提升请求并发度，从而充分利用缓存和对象存储资源，提高整体 I/O 性能。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;企业版还有一些进阶配置：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;max read ahead&lt;/code&gt;：用于设定预读的最大范围。  &lt;/li&gt;
&lt;li&gt;&lt;code&gt;initial read ahead&lt;/code&gt;： 用于设置开启预读时的预读窗口大小，默认以 4MB 块为单位。  &lt;/li&gt;
&lt;li&gt;&lt;code&gt;read ahead ratio&lt;/code&gt;： 是去年新增的配置，用于控制大文件随机读取时的预读比例，减少读放大导致的带宽瓶颈。过于激进的预读可能对随机读取性能产生负面影响，&lt;code&gt;read ahead ratio&lt;/code&gt; 可用于缓解该问题。在 AI 场景中，遇到大文件顺序或随机访问导致的带宽或 IOPS 瓶颈时，可通过调整这些参数优化整体性能。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;02 JuiceFS 基准 I/O 测试与瓶颈分析&lt;/h2&gt;
&lt;p&gt;在介绍 JuiceFS 在常见 AI 场景下的性能调优之前，先通过连续读和随机读基准测试观察系统在理想条件下的 I/O 表现，以理解不同访问模式下的吞吐量与延迟，为后续 AI/ML 场景的读写模式提供参考。&lt;/p&gt;
&lt;h3&gt;连续读性能&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;在 JuiceFS 中，连续读的性能通常主要受带宽因素影响。在冷读场景下，性能主要受对象存储带宽约束；而在分布式缓存场景下，网络带宽可能成为瓶颈&lt;/strong&gt;。例如，一台配备 40 Gbps 网卡的机器，其实际可用带宽可能不足 5 Gbps。此外，FUSE 层的用户态与内核态转换开销也会限制单线程吞吐，经测试单线程读取文件的带宽约为 3.5 Gbps。要突破此限制，需要采用多线程或多并发策略以充分利用存储与网络资源。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: left;"&gt;threads&lt;/th&gt;
&lt;th style="text-align: left;"&gt;bw(GB/s)&lt;/th&gt;
&lt;th style="text-align: left;"&gt;bw/threads&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;3.5&lt;/td&gt;
&lt;td style="text-align: left;"&gt;3.5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;2&lt;/td&gt;
&lt;td style="text-align: left;"&gt;6.3&lt;/td&gt;
&lt;td style="text-align: left;"&gt;3.15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;3&lt;/td&gt;
&lt;td style="text-align: left;"&gt;9.5&lt;/td&gt;
&lt;td style="text-align: left;"&gt;3.16&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;4&lt;/td&gt;
&lt;td style="text-align: left;"&gt;9.7&lt;/td&gt;
&lt;td style="text-align: left;"&gt;2.43&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;6&lt;/td&gt;
&lt;td style="text-align: left;"&gt;14.0&lt;/td&gt;
&lt;td style="text-align: left;"&gt;2.33&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;8&lt;/td&gt;
&lt;td style="text-align: left;"&gt;17.0&lt;/td&gt;
&lt;td style="text-align: left;"&gt;2.13&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;10&lt;/td&gt;
&lt;td style="text-align: left;"&gt;18.6&lt;/td&gt;
&lt;td style="text-align: left;"&gt;1.9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;15&lt;/td&gt;
&lt;td style="text-align: left;"&gt;21&lt;/td&gt;
&lt;td style="text-align: left;"&gt;1.4&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;在性能测试中，单线程连续读带宽约为 3.5 Gbps，随着线程数增加，整体吞吐量可逐渐接近网络带宽上限。为了方便评估自身环境的性能上限，JuiceFS 提供了 &lt;code&gt;bj bench&lt;/code&gt; 子命令，可用于测试对象存储带宽。&lt;/p&gt;
&lt;p&gt;在实际业务中，缓存往往比直接访问对象存储更常见。此时，可通过增大 &lt;code&gt;buffer size&lt;/code&gt; 提高后台预读请求数，从而提升并发度并改善整体吞吐。例如，将 buffer size 调整至 400 MB（对应 100 个 4 MB 块的后台预读请求）后，并发度显著提升，整体吞吐量随之增强。&lt;/p&gt;
&lt;h3&gt;随机读性能&lt;/h3&gt;
&lt;h4&gt;低并发随机读&lt;/h4&gt;
&lt;p&gt;在低并发且非异步访问场景下，每个请求需等待前一个完成后才能发出，因此延迟对整体性能的影响尤为显著。&lt;strong&gt;I/O 延迟可能来源于多方面，包括元数据查询延迟、对象存储访问延迟，以及本地缓存或分布式缓存读取延迟&lt;/strong&gt;。在分析随机读性能时，需要重点关注这些延迟因素。&lt;/p&gt;
&lt;p&gt;在 4 KB 随机冷读场景下，若 IOPS 仅为 8，且对象存储延迟约 125 毫秒，则可计算出系统并发度约为 1（8 IOPS × 125 ms ≈ 1000 ms）。&lt;/p&gt;
&lt;p&gt;这表明当前处于近似单并发、请求串行阻塞的状态。在这种情况下，优化重点通常不在于进一步提升并发，而在于缩短访问路径、降低单次请求延迟，例如将数据预热至本地缓存。完成预热后，随机读路径可由对象存储切换至本地缓存，IOPS 可提升至约 12,000，接近本地磁盘的 I/O 水平。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;juicefs stats 命令查看性能&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;juicefs stats 命令查看性能&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;预热后性能&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;预热后性能&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;h4&gt;高并发随机读&lt;/h4&gt;
&lt;p&gt;高并发随机读通常发生在并发数较高或采用异步 I/O 的场景下，其性能瓶颈主要体现在 IOPS 限制上。IOPS 包括元数据 IOPS、对象存储 IOPS 以及缓存 IOPS。通过 JuiceFS，可以观察这些指标，从而确定性能瓶颈所在。此外，客户端机器的资源（如 CPU 和内存）也可能对性能产生影响，但这类瓶颈相对容易监测。&lt;/p&gt;
&lt;p&gt;在冷读场景下，以通过 Libaio 发起的随机读为例，对象存储侧的 IOPS 上限接近 7,000/s。若启用缓存并完成数据预热，访问路径将由对象存储切换至缓存层，IOPS 可进一步提升至 20,000 以上，说明高并发随机读的瓶颈会随访问路径变化而发生转移。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;预热前&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;预热前&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;预热后&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;预热后&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;有兴趣深入了解 JuiceFS 的完整数据访问链路，请参考博客：&lt;a href="https://juicefs.com/zh-cn/blog/engineering/juicefs-read-performance#05-%E8%BF%9E%E7%BB%AD%E8%AF%BB%E4%B8%8E%E9%9A%8F%E6%9C%BA%E8%AF%BB%E6%B5%8B%E8%AF%95"&gt;一文详解 JuiceFS 读性能——预读、预取、缓存、FUSE 和对象存储&lt;/a&gt;。&lt;/p&gt;
&lt;h2&gt;03 常见 AI 场景下的 I/O 特性与性能调优&lt;/h2&gt;
&lt;h3&gt;大文件顺序读场景&lt;/h3&gt;
&lt;p&gt;大文件顺序读取的典型应用场景之一是模型加载，例如通过 Pickle 序列化保存的 PT 文件。在此过程中，性能受到两方面限制：一方面，Pickle 的反序列化效率决定了数据处理速度；另一方面，数据读取通常为单线程，受 FUSE 带宽上限和 CPU 性能约束。为提升吞吐量，可通过增加并发度实现多线程或分片加载，从而充分利用 I/O 能力。在大文件顺序读取的场景下，若能够将数据集完全缓存至本地，可获得最佳性能；若仅需按需读取数据，则实现相对简单。&lt;/p&gt;
&lt;p&gt;关于大文件顺序读场景性能优化，可参考&lt;a href="https://juicefs.com/zh-cn/blog/solutions/building-high-throughput-cache-pool-resilience-with-juicefs"&gt;如何构建 70GB/s 吞吐的缓存池&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;海量小文件场景&lt;/h3&gt;
&lt;p&gt;在计算机视觉和多模态任务中，训练数据集通常由大量单独文件组成，例如单张图片、视频帧或文本标注文件。这类海量小文件场景对元数据服务的压力较大。&lt;/p&gt;
&lt;p&gt;海量小文件场景下，元数据性能影响显著。一方面，每个文件的数据量较小；另一方面，存放大量小文件的目录元数据访问效率较低。&lt;strong&gt;对于只读负载，可通过开启客户端元数据缓存并延长缓存周期来提升性能。此外，数据读取层的 IOPS 压力也更大，因为小文件无法充分利用预读机制，导致请求更加碎片化。常用的优化措施包括增加本地缓存容量，对于商业版本可进一步采用横向扩展的分布式缓存集群&lt;/strong&gt;。由于小文件难以受益于预读机制，其延迟表现也相对较高。&lt;/p&gt;
&lt;p&gt;该场景性能优化可参考：&lt;a href="https://juicefs.com/zh-cn/blog/user-stories/horizon-robotics-juicefs-small-file-multi-cloud-optimization"&gt;海量小文件 + 多云协同：地瓜机器人 JuiceFS 存储优化之路&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;大文件随机读场景&lt;/h3&gt;
&lt;p&gt;此类场景在 AI 训练中较为常见，例如按样本随机访问 TFRecord、HDF5 或 LMDB 格式的数据集等。以模型加载为例，若数据集格式为随机读且每次读取的大小为数据集样本大小（如 1MB 至 4MB 的图片或短视频），则预读机制可能导致带宽浪费。此类场景通常可通过多并发加载来突破 IOPS 瓶颈，可采取以下措施：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;增加数据加载的 reader 线程数。  &lt;/li&gt;
&lt;li&gt;使用异步 IO 提高并发度，尽量打满 IOPS。  &lt;/li&gt;
&lt;li&gt;完善缓存体系，如提前将数据映射至缓存以提高底层 IOPS 性能。  &lt;/li&gt;
&lt;li&gt;调整 read ahead ratio 参数（如设为 0.5），以降低预读带来的带宽浪费。例如，原本 4MB 的顺序读会预读 4MB 数据，调整后仅预读 2MB 数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本文从性能角度分析了 JuiceFS 的架构设计、基准 I/O 测试以及在典型 AI 场景下的调优方法，为读者提供关于系统性能的入门参考。JuiceFS 已在大量生产环境中得到应用，其分布式架构在性能与成本之间提供了可行的平衡方案。&lt;/p&gt;
&lt;p&gt;欢迎在评论区分享或讨论实际使用中的经验与策略。&lt;/p&gt;&lt;/div&gt;</description><pubDate>Fri, 03 Apr 2026 02:50:00 +0000</pubDate><guid>https://www.juicefs.com/zh-cn/blog/engineering/juicefs-ai-workload-performance-optimization</guid></item><item><title>ARM 架构 JuiceFS 性能优化：基于 MLPerf 的实践与调优</title><link>https://www.juicefs.com/zh-cn/blog/engineering/arm-juicefs-performance-optimization-mlperf-tuning</link><description>&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;随着国产芯片与 ARM 生态的快速发展，如何在 ARM 平台上构建高性能存储基础设施成为技术焦点。Linaro 是一个专注于 Arm 生态和开源软件的国际化技术组织，联合产业链上下游厂商解决共性问题，并协助企业客户在开源基础上完成产品化落地。Linaro 团队在 MLPerf Storage 测试中，对 JuiceFS 社区版（元数据采用 Redis）进行了系统压测，覆盖多种典型机器学习训练负载。&lt;/p&gt;
&lt;p&gt;测试结果显示，系统性能在很大程度上受内存带宽和元数据访问效率影响，JuiceFS 的吞吐能力直接决定 GPU 利用率及训练效率。通过 UNet3D、ResNet-50 和 CosmoFlow 等负载的测试，分析发现：单机场景下，GPU 利用率主要受内存拷贝延迟限制；在双机或多机场景下，元数据访问和节点间同步成为主要瓶颈。文章同时提供了针对这些瓶颈的调优思路与实践结果。&lt;/p&gt;
&lt;p&gt;总体来看，大规模 AI 训练性能调优是一个系统工程，需要从存储系统、内存带宽、CPU 调度、缓存策略等多方面协同优化，才能在 ARM 平台上实现高效的深度学习训练数据供给。&lt;/p&gt;
&lt;h2&gt;01 Arm64 与 x86_64 架构差异与并发特性概述&lt;/h2&gt;
&lt;p&gt;相比 x86，Arm 的应用范围不断扩大，已从移动端延伸至 IoT、可穿戴设备、PC、汽车和服务器，其高能效比（performance per watt）是广泛采用的关键原因。&lt;/p&gt;
&lt;p&gt;从架构设计上看，Arm 属于 RISC（Reduced Instruction Set Computer，精简指令集计算机），x86 属于 CISC（Complex Instruction Set Computer，复杂指令集计算机）。这种设计差异也影响了处理器的执行方式。Arm64 的指令长度固定为 4 字节，而 x86 指令长度可变，大约在 1–15 字节 之间，因此 x86 往往需要更复杂的译码器。相比之下，Arm 的指令更简洁，也更依赖编译器和代码生成阶段对指令的有效组织，所以需要更长的编译时间。&lt;/p&gt;
&lt;p&gt;从工程师可感知的角度来看，还有一些架构差异会直接影响程序行为。&lt;strong&gt;很多在 x86 上看起来符合直觉的代码，在 Arm 上未必如此，后面要讲到的几个容易踩坑的点，基本都与这些底层差异有关&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;其中一个典型问题是原子操作对地址对齐有要求。无论是 LL/SC（Load-Link/Store-Conditional），还是 LSE（Large System Extensions），在执行原子加减等读改写操作时，通常都要求访问地址满足对齐条件。较新的 LSE2 对这一限制有所放宽，开始支持 16-byte window 内的非对齐访问。数据对齐对于 x86 来说不是必须的，但保持良好对齐有助于提升性能。参考文档: &lt;a href="https://developer.arm.com/documentation/ddi0487/maa/-Part-B-The-AArch64-Application-Level-Architecture/-Chapter-B2-The-AArch64-Application-Level-Memory-Model/-B2-8-Alignment-support/-B2-8-2-Alignment-of-data-accesses?lang=en#chdffegj"&gt;Arm Architecture Reference Manual for A-profile architecture&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;另一个需要重点关注的特点是，Arm 采用的是弱内存序模型（weakly ordered / relaxed memory model），差别体现在对内存访问顺序的约束强弱不同。在多线程场景下，同样的读写操作，在 x86 上通常更容易表现为接近程序书写顺序，而在 Arm 上则允许更多重排序，因此其他线程观察到的读写顺序可能与源码顺序不一致。在 Arm 上出现的异常需要特别考虑内存序的影响。更多细节可参考 Arm 白皮书：&lt;a href="https://developer.arm.com/documentation/107630/1-0/?lang=en"&gt;Synchronization Overview and Case Study on Arm Architecture&lt;/a&gt;。&lt;/p&gt;
&lt;h2&gt;02 JuiceFS 与 MLPerf 概述&lt;/h2&gt;
&lt;p&gt;JuiceFS 是一款开源高性能分布式文件系统，基于对象存储构建，在充分利用对象存储低成本优势的同时，提供接近传统文件系统的使用体验。它支持 POSIX、HDFS SDK、Python SDK 以及 S3 兼容接口，并能适配不同类型的应用和数据处理框架；同时支持云原生扩展、数据安全与压缩，可广泛应用于 AI 训练、推理、大数据处理等场景。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;1JuiceFS 架构图.drawio&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;JuiceFS 社区版架构图&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;为评估 JuiceFS 在 AI 训练等高负载场景下的数据供给能力，可采用 MLPerf Storage 基准测试。该测试由 MLCommons 开发，重点衡量存储系统能否持续高效向计算侧提供数据。&lt;/p&gt;
&lt;p&gt;2.0 版本将测试分为训练负载和检查点负载两类，其中训练负载包括 3D U-Net、ResNet-50 和 CosmoFlow，三者在样本大小和访问特征上存在显著差异，并设置了最低 GPU 利用率要求：3D U-Net 与 ResNet-50 为 90%，CosmoFlow 为 70%。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;MLPerf Storage 2.0 训练负载&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;MLPerf Storage 2.0 训练负载&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;在测试流程中，数据首先从存储系统读入主机内存，再进入计算阶段。训练耗时由模拟方式复现，以模拟真实训练场景的数据流，从而无需实际部署 GPU，降低实验门槛并提升操作便利性。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;MLPerf Storage 数据流&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;MLPerf Storage 数据流&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;h2&gt;03 MLPerf Storage v2.0 测试原理与调优&lt;/h2&gt;
&lt;p&gt;在介绍具体的模型测试结果之前，需要先了解分布式训练的数据访问原理，有助于读者明白 GPU 利用率、存储吞吐和性能瓶颈的成因，从而更好地理解后续的测试结果和调优策略。&lt;/p&gt;
&lt;p&gt;分布式机器学习通常采用数据并行方式，即多个并行进程共享同一数据集，每个进程分别负责读取和处理对应的训练批次。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;分布式训练数据访问原理示意图&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;分布式训练数据访问原理示意图&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;MLPerf Storage 的训练测试也遵循这一思路，每个训练进程按批次从存储系统读取数据，并通过模拟计算来评估存储系统的持续供数能力。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;MLPerf Storage 训练数据流示意图&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;MLPerf Storage 训练数据流示意图&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;p&gt;为了理解测试中性能表现的来源，还需要理解 JuiceFS 客户端的数据处理链路。使用 JuiceFS 进行测试时，如图所示，其执行流程大致可分为三部分。&lt;/p&gt;&lt;/div&gt;
&lt;div class="w-block-ImageWithCaption block-ImageWithCaption"&gt;&lt;dl&gt;
    &lt;dt&gt;image&lt;/dt&gt;
    &lt;dd&gt;JuiceFS 客户端线程与数据流示意图&lt;/dd&gt;
    &lt;dt&gt;caption&lt;/dt&gt;
    &lt;dd&gt;JuiceFS 客户端线程与数据流示意图&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
&lt;div class="w-block-markdown block-markdown"&gt;&lt;ul&gt;
&lt;li&gt;左侧：应用侧 I/O 线程，例如 &lt;code&gt;fio&lt;/code&gt; 或 MLPerf Storage 的 &lt;code&gt;DataLoader&lt;/code&gt; 线程，负责发起 &lt;code&gt;read/write&lt;/code&gt; 请求并等待请求完成。  &lt;/li&gt;
&lt;li&gt;中间：FUSE 守护进程中的请求处理主 &lt;code&gt;goroutine&lt;/code&gt;，负责接收并处理来自内核态的 FUSE 请求，将文件数据放入内存缓冲区和缓存，并触发后端元数据与对象存储访问。  &lt;/li&gt;
&lt;li&gt;右侧：Meta client 和 ObjectStore client 的异步 &lt;code&gt;goroutine&lt;/code&gt;，负责与后端 MetaDB 和 ObjectStore 集群进行数据与元数据交互。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从性能分析的角度看，这条链路需要重点关注两类问题。第一类是数据拷贝，对应图中的 2.1、3、4、5、6 等步骤，这些位置都会带来额外的内存复制开销，因此往往是分析延迟和 CPU 开销时的重点。&lt;/p&gt;
&lt;p&gt;第二类是同步与异步边界。从图中可以看出，1、2、3、4、5、6 这些步骤总体属于同步路径，也就是请求发起后，需要等待当前阶段完成才能继续向下推进；而 7 属于异步路径，由后台 &lt;code&gt;goroutine&lt;/code&gt; 负责与后端存储交互。&lt;/p&gt;
&lt;h3&gt;测试 1：Unet 3d&lt;/h3&gt;
&lt;p&gt;在这个测试中，样本为 146 MiB 的图像文件，我们主要关注大块数据的读取性能。测试结果显示：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;单机环境下最高可稳定运行 5 块 GPU，GPU 利用率约为 50%，  &lt;/li&gt;
&lt;li&gt;而双机场景可支持 10 块 GPU，GPU 利用率同样约为 50%。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为了提升数据读取效率，对训练参数进行了优化：将 &lt;code&gt;reader&lt;/code&gt; 并发线程数从 4 调整为 16，以加快数据生成速度，并将数据读取方式改为 direct I/O，以减少缓冲区和内存拷贝开销。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;业务指标显示，当单机挂载 6 块 GPU 时，GPU 利用率仅为 83%，对应带宽约为 15.1 GB/s，未达到预期的高利用率目标&lt;/strong&gt;。进一步使用 FIO 对存储侧进行测试后发现，其带宽同样约为 15.1 GB/s，&lt;strong&gt;说明此时系统瓶颈已经落在 JuiceFS 客户端带宽 上，而不是 GPU 计算侧本身&lt;/strong&gt;。&lt;/p&gt;
&lt;h4&gt;优化分析 1：绑定 CPU&lt;/h4&gt;
&lt;p&gt;为了深入分析客户端带宽受限的原因，我们对进程进行了 CPU 绑定，将其固定在 CPU1（NUMA 2、3 节点）运行。通过工具观察，48 个 CPU 核心几乎全部占满，进一步分析 top-down、memory 和 miss 指标发现，系统表现出明显 Memory Bound，主要耗时集中在内存拷贝上。这说明，在 CPU 绑定场景下，JuiceFS 性能瓶颈主要来自 CPU 处理能力和跨 NUMA 节点内存拷贝带来的额外延迟。&lt;/p&gt;
&lt;h4&gt;优化分析 2： 不进行 CPU 绑定&lt;/h4&gt;
&lt;p&gt;为了理解系统在更通用条件下的带宽限制，我们进一步观察了不绑定 CPU 的情况。通过观察可以看到，CPU 并未被完全用满，但 devkit tuner numafast 指标显示，系统中的 remote 内存访问比例高达约 80%。这意味着，大量内存访问已经跨越本地 NUMA 节点，甚至可能跨越 CPU socket，从而引入了显著的带宽损失和访问时延。&lt;/p&gt;
&lt;p&gt;从硬件带宽特性看，跨片内存访问本身就存在明显限制。例如，在 Arm 平台上，跨 socket 的理论物理带宽约为 60 GB/s；进一步通过实测，跨片 copy 带宽在 Arm1 上约为 48 GB/s，而在两组 x86 平台上分别约为 37 GB/s 和 28 GB/s。&lt;/p&gt;
&lt;p&gt;这说明，在不绑定 CPU 的情况下，虽然计算核表面上没有被完全耗尽，但大量跨节点、跨 socket 的远端内存访问已经成为新的主要开销来源。因此，可以推测，此时 JuiceFS 带宽无法继续提升，很可能并不是单纯受限于 CPU 算力，而是受限于跨片内存访问的带宽与时延。&lt;strong&gt;换言之，系统瓶颈已经从“本地 CPU 忙不过来”转移为“远端内存访问代价过高”&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;综合来看，在两种场景下，JuiceFS 带宽无法提升的原因并不相同：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;绑定 CPU 时，主要受限于 CPU 资源消耗以及大量内存拷贝带来的访问开销；  &lt;/li&gt;
&lt;li&gt;不绑定 CPU 时，主要受限于高比例 非本地内存访问，尤其可能是跨 socket 访问带来的带宽和时延损失。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;测试 2：Resnet50&lt;/h3&gt;
&lt;p&gt;ResNet-50 测试的单个样本较小，单个样本大小约为 150 KiB，每个 batch 包含 400 个样本，每个 batch 的总数据量约 58.5 MiB。本次 I/O 测试关注 GPU 高并发下的数据加载效率及训练吞吐。测试显示系统可在大规模 GPU 下维持较高利用率：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;单机：50 块 GPU，GPU 利用率 95%，带宽约 9.2 GB/s  &lt;/li&gt;
&lt;li&gt;双机：96 块 GPU，GPU 利用率 90%，带宽约 16.9 GB/s&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在测试过程中，我们将关键参数 &lt;code&gt;reader.read_threads&lt;/code&gt; 从 8 调整为 1，对于该模型（中等大小的图像模型），单线程即可满足数据供给需求。&lt;/p&gt;
&lt;h4&gt;优化分析 1： 单机性能瓶颈与内存带宽影响&lt;/h4&gt;
&lt;p&gt;在单机配置 55 块 GPU 时，GPU 利用率下降至 86%，带宽仍为 9.2 GB/s，表明系统瓶颈已转移至 JuiceFS 客户端带宽。&lt;/p&gt;
&lt;p&gt;进一步分析发现，ResNet-50 测试采用 Buffer I/O 模式，除了读取数据外，处理数据集时的 内存拷贝会消耗一部分内存带宽。&lt;/p&gt;
&lt;p&gt;系统内存拷贝带宽受内存通道数、内存频率及 CPU 频率影响。通过对多台配置不同的机器进行 stream 测试，得到的单机顺序读带宽与系统内存带宽测得的可比带宽一致，&lt;strong&gt;表明读数据吞吐能力在很大程度上取决于系统内存带宽。对于需要高吞吐、高 GPU 利用率的训练任务，建议优先选择内存带宽较高的机型，可显著提升数据供给能力和训练效率&lt;/strong&gt;。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: left;"&gt;&lt;/th&gt;
&lt;th style="text-align: left;"&gt;单 CPU 内存拷贝带宽数据&lt;/th&gt;
&lt;th style="text-align: left;"&gt;JuiceFS 单机部署读带宽&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Arm3&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Arm3: 171 GB/s&lt;/td&gt;
&lt;td style="text-align: left;"&gt;25.3 GiB/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Arm2&lt;/td&gt;
&lt;td style="text-align: left;"&gt;114 GB/s&lt;/td&gt;
&lt;td style="text-align: left;"&gt;21.6 GiB/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Arm1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;106 GB/s&lt;/td&gt;
&lt;td style="text-align: left;"&gt;18.3 GiB/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;x862&lt;/td&gt;
&lt;td style="text-align: left;"&gt;90 GB/s&lt;/td&gt;
&lt;td style="text-align: left;"&gt;17.9 GiB/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;x861&lt;/td&gt;
&lt;td style="text-align: left;"&gt;82 GB/s&lt;/td&gt;
&lt;td style="text-align: left;"&gt;16.6 GiB/s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;优化分析 2：双机扩展瓶颈与分布式限制&lt;/h4&gt;
&lt;p&gt;在多节点部署中，除了单机性能限制外，跨节点内存访问、网络传输和元数据延迟会成为新的瓶颈，因此在单机分析之后进行双机测试，有助于识别这些分布式约束并指导系统优化。&lt;/p&gt;
&lt;p&gt;在双机场景下，理论上可以支持 100 块 GPU，但实际测试中只能达到 96 块 GPU。通过分析发现，每个操作的读取延迟有所增加。尽管文件数据已缓存在本地盘上，元数据访问延迟仍然成为主要限制因素。&lt;/p&gt;
&lt;p&gt;为解决这一问题，对系统进行了多方面优化：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;将 CPU 核心分组，保证训练线程与 I/O 线程在同一 NUMA 节点上运行。  &lt;/li&gt;
&lt;li&gt;将纯数据处理和元数据访问分别分配到不同 CPU 核心和存储路径上。  &lt;/li&gt;
&lt;li&gt;调整 Redis 缓存和本地缓存策略，减少高并发访问元数据时的延迟。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;经过上述调优后，双机场景能够稳定支撑 100 块 GPU 运行，GPU 利用率达到预期水平。&lt;/p&gt;
&lt;h3&gt;测试 3：cosmoflow&lt;/h3&gt;
&lt;p&gt;与之前的模型相比，这个模型的单样本数据量更小，这也意味着对 I/O 和元数据访问的要求更高。在单机和双机场景下，CosmoFlow 测试显示：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;单机：最高稳定 10 块 GPU（偶尔可撑到 12 块 GPU），GPU 利用率约 75%，带宽约 5.6 GB/s  &lt;/li&gt;
&lt;li&gt;关键参数调整：将 &lt;code&gt;reader.read_threads&lt;/code&gt; 从 4 调整为 1，每次读取 batch 数据量为 2 MiB，单线程即可满足数据供给需求。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;优化分析 1：单机瓶颈：内存拷贝限制 GPU 利用率&lt;/h4&gt;
&lt;p&gt;当尝试增加 GPU 数量超过 10 块时，发现 GPU 利用率下降。分析日志和性能数据后发现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据读取时间增加，而元数据访问延迟变化不大。  &lt;/li&gt;
&lt;li&gt;文件数据已缓存在本地盘上，磁盘队列未满，延迟也不高，因此瓶颈不在存储设备。  &lt;/li&gt;
&lt;li&gt;使用性能分析工具观察发现，关键瓶颈操作主要集中在 内存拷贝（memcopy），数据读取流程中多次拷贝操作的延迟累积，导致整体读取时间增加。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;由此推测，当系统使用更多内存带宽时，内存拷贝延迟成为限制读取性能和 GPU 利用率的主要因素。&lt;/p&gt;
&lt;h4&gt;优化分析 2：双机瓶颈：分布式同步与元数据延迟&lt;/h4&gt;
&lt;p&gt;在双机场景下，尝试 20 块 GPU 时，第一轮测试 GPU 利用率明显偏低。进一步分析发现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一台机器已开始训练，而另一台机器仍在进行 Dataset 预处理，包括读取文件列表和分片操作。  &lt;/li&gt;
&lt;li&gt;由于 CosmoFlow 数据量较大，高索引文件的读取耗时较长，导致两台机器未能同步开始训练，第一轮 GPU 利用率下降。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为解决该问题，在代码中加入同步机制，确保所有节点在开始训练前完成 Dataset 预处理。经过该调整后，双机测试能够稳定支撑 20 块 GPU，GPU 利用率达到预期水平。&lt;/p&gt;
&lt;h2&gt;04 总结&lt;/h2&gt;
&lt;p&gt;首先，MLPerf Storage 通过不同样本、文件和 batch 大小的组合，考察文件系统的各项能力，包括大中小块顺序读能力、文件并发性能、总读带宽、元数据访问时延、文件读取时延以及文件操作的稳定性。在只读文件场景下，充分利用高速近端缓存（包括原数据和元数据缓存）可以显著提升读取性能。需要注意，文件越小，对 IOPS 和延迟的要求越高。&lt;/p&gt;
&lt;p&gt;其次，我们发现系统的内存和带宽对性能影响显著。在 Memory copy 密集型的应用中，内存拷贝不仅消耗内存带宽，同时也占用 CPU，表面上会出现“CPU 忙”的假象，实际上 CPU 大部分时间是在等待数据。测试结果显示，系统内存带宽对 JuiceFS 的吞吐能力有决定性影响，这也为选择服务器提供了参考标准：内存带宽越高的系统，其存储吞吐性能也越好。&lt;/p&gt;
&lt;p&gt;第三，Go 运行时对 NUMA 的感知有限，对于大规模 CPU 核心运行场景，性能可能不如小规模核心运行。对于多 NUMA 系统，应尽量避免跨 NUMA，尤其是跨 CPU socket 的访问，因为跨 socket 内存带宽通常较低（约几十 GB/s），会增加延迟并影响整体性能。因此，实际部署时只需要分配足够的 CPU 核心即可，无需过度使用全部核心，以避免额外的内存访问延迟。&lt;/p&gt;
&lt;p&gt;第四，在系统层面还有一些潜在优化点。例如，对于 Memory copy 密集的操作，部分 Arm 新系统提供了针对内存访问的指令优化，我们与 Arm 社区合作，将配置提升推送到社区中，新系统可以显著提升内存拷贝效率，在部分场景中带宽提升可达数十个百分点。&lt;/p&gt;
&lt;p&gt;此外，对于涉及大量内核与用户态交互的操作，例如文件读写和元数据处理，可以通过优化用户态与内核态的交互，减少不必要的调用次数，从而降低延迟。实践中也发现，将文件处理尽量集中在同一生产节点内，避免跨 NUMA 或跨 socket 的访问，可以进一步提升性能和稳定性。&lt;/p&gt;
&lt;p&gt;最后，系统配置优化也体现在缓存策略上。例如，在单机高负载场景下，通过调整 JuiceFS 的内存缓存策略，减少无效内存带宽占用，可以有效提高 GPU 利用率和存储吞吐。整体来看，MLPerf Storage Benchmark 是一个系统工程，需要文件系统、内存带宽、CPU 调度和缓存策略等多方面配合，才能达到最优性能。关于此次测试详细信息，可&lt;a href="https://docs.qq.com/doc/DSWZtaFFNYVZVbXRX?nlc=1"&gt;查看文档&lt;/a&gt;。&lt;/p&gt;&lt;/div&gt;</description><pubDate>Fri, 27 Mar 2026 07:05:00 +0000</pubDate><guid>https://www.juicefs.com/zh-cn/blog/engineering/arm-juicefs-performance-optimization-mlperf-tuning</guid></item></channel></rss>