合合信息:基于 JuiceFS 构建统一存储,支撑 PB 级 AI 训练

合合信息是一家专注于智能文字识别、图像处理、自然语言处理、知识图谱与大数据挖掘的科技公司,依托自主研发的 AI 与大数据技术,已在上交所科创板上市。公司主要 C 端产品包括扫描全能王、名片全能王和启信宝。

随着 AI 训练平台规模持续扩展,公司积累了千亿级文件和百 PB 级数据,覆盖 NLP、CV 等多种任务类型,存储需求愈发复杂。原有架构中,BeeGFS 作为高速并行存储提供 RDMA 访问,但容量有限;SeaweedFS 提供大容量对象存储,但性能存在瓶颈,且与在线服务混合部署,易出现资源抢占问题。在这种架构下,数据迁移频繁、访问路径割裂、资源利用率低下成为主要瓶颈。

为应对这些挑战,合合信息引入 JuiceFS 构建统一的存储访问架构,并结合 BeeGFS 提供分布式缓存能力。JuiceFS 目前稳定支撑数十亿级文件、十 PB 级数据存量与 PB 级日增数据,平均缓存命中率超过 90%,显著提升了 AI 训练与大数据任务的 I/O 性能。该架构整合了高速缓存与低成本对象存储的访问路径,打通多源数据流动,提升了整体系统的资源调度效率,并支持与线上业务的高效混合部署。

01 AI 平台与早期存储架构

AI 训练平台主要服务于各类算法模型的训练与推理,大数据平台则侧重于支撑海量数据的存储与计算分析。无论是 AI 模型的迭代,还是大数据挖掘任务,均对计算资源与存储性能提出了较高要求。为提升整体资源利用率,我们在架构上引入了计算层与存储层的离线混合部署策略,通过统一调度和资源复用,实现对有限计算与存储资源的高效利用。

早期分布式文件存储架构:BeeGFS + SeaweedFS

早期我们的任务主要以单机训练为主,数据集通常依赖训练服务器本地存储。随着近年来多卡及多机训练任务的发展,训练对跨节点共享数据集的需求日益增加,这促使我们引入分布式存储以适应此类需求。

针对这一变化,我们先后引入了两个开源项目构建存储体系。首先,我们基于 BeeGFS 和训练节点上的 SSD 构建了一套分布式全闪存存储系统。该方案采用与训练服务器混合部署的方式,能够充分利用已有的计算资源,实现较高的存储性能和较低的访问延迟,适合对 I/O 要求较高的训练任务。但由于其部署规模受到训练节点数量的限制,整体存储容量较小,难以支撑大规模数据集。

考虑到训练任务的数据总量较大,我们又部署了另一套基于 SeaweedFS 的存储系统。SeaweedFS 原本用于对象存储,同时支持基础的 POSIX 协议,因此可以作为分布式文件系统使用。我们将其部署在线上业务的物理机房中,使用机械硬盘作为主要存储介质。相较于 BeeGFS,这套系统的总容量提升了数十倍。然而由于其与在线业务共用资源,为避免干扰业务,我们对其性能做了限制,因此在 I/O 性能方面存在一定程度的瓶颈。

通过这两套系统的组合部署,我们实现了一种分层存储架构:BeeGFS 提供高性能但容量有限的高速存储,SeaweedFS 提供容量大但性能受限的低速存储。这种架构能够在实际应用中灵活适配不同类型的训练任务,对稳定支持大规模 AI 训练提供了有效保障。

计算作业管理策略:解耦存储,提高 GPU 利用率

以下是我们在训练任务的 GPU 计算资源调度方面所做的一些工作。早期阶段,GPU 卡往往是按人或按业务静态分配的,也就是说某些卡长期归属于特定用户或项目。这种方式在实际运行中效率较低:有些用户虽然申请到了卡,但并未充分使用;而另一些有紧急训练需求的用户则无法及时获取资源,只能依靠人工协调,资源使用存在明显的浪费。

为了解决这一问题,我们引入了 Slurm 作为训练任务的调度系统,实现对全局 GPU 资源的统一管理。通过任务调度,我们可以在不同任务之间动态分配 GPU,提升整体资源利用率。调度系统由专门的任务调度团队负责运营,他们持续优化调度策略,以确保训练任务在资源层面得到更合理的分配。

结合前述的分布式存储体系和 GPU 调度机制,我们初步实现了计算与存储的解耦。一方面,通过任务调度提升了 GPU 资源的总体利用率;另一方面,借助统一的存储系统,训练任务无需频繁进行大规模数据拷贝,从而简化了任务部署流程,提升了整体系统的运行效率和可扩展性。

02 存储系统的新需求与架构演进

在这一套系统运行一段时间之后,随着业务量的持续增长以及数据集规模的迅速膨胀,我们对存储层提出了新的需求,主要集中在以下三个方面:

首先是 POSIX 兼容性。由于各业务线的工程师在使用不同的算法训练框架,有些还会运行自研程序,因此我们需要存储系统具备尽可能完整的 POSIX 接口兼容性,以适配多样化的上层训练框架。然而我们此前使用的 SeaweedFS,在这方面存在一定局限。它本质上仍以对象存储为主,POSIX 支持不完善,在训练任务运行过程中遇到了不少兼容性相关的问题。

其次是统一的访问路径管理。由于 BeeGFS 提供的高速存储容量有限,而用户普遍倾向于将数据放在性能更高的存储中,这导致使用压力持续增大。为了缓解这一矛盾,我们需要在 BeeGFS 与 SeaweedFS 之间频繁迁移数据。即使我们实现了一定程度的自动化缓存控制,在数据集规模较大的情况下,数据搬迁仍需花费大量时间,整体效率较低,且增加了人工介入成本。

第三是资源利用率的平衡问题。SeaweedFS 部署于与在线业务共用的物理服务器上,受限于对线上业务资源的保护,其整体 I/O 性能存在上限。而在高并发训练任务同时访问时,SeaweedFS 性能容易达到瓶颈。相比之下,BeeGFS 虽然具备较高的性能,但由于容量限制,其资源利用率并不理想。因此我们希望能够有一套机制,在保持性能的前提下,实现冷、热存储资源间的动态平衡,提高整体系统效率。

基于以上三点核心需求,我们开展了新一轮的技术调研,并最终引入了 JuiceFS 作为新的存储解决方案。

03 新架构:基于 JuiceFS 的存储体系重构与分布式缓存优化实践

我们基于 JuiceFS 重新搭建了训练任务所使用的存储系统。下图所示为 JuiceFS 官方提供的参考架构,在此基础上我们根据自身需求做了一些调整。

在架构左侧,JuiceFS 原图中标注为 "local disk" 的部分,原意是用于本地缓存。在我们的实际部署中,将此缓存目录指向了 BeeGFS 文件系统。这样做的好处是:我们使用一个共享的分布式高性能文件系统(BeeGFS)作为 JuiceFS 的缓存层。借助这一调整,在多卡训练任务场景中,只需一个节点从远端存储中读取数据,其他节点即可直接从共享缓存中读取,避免重复下载。

这一机制还使得缓存预热更加高效。我们只需在一个节点上执行预热任务,之后所有节点均可从已预热的共享缓存中读取数据,极大提升了训练启动效率和整体带宽利用率。

在架构右侧,我们仍保留了 SeaweedFS 作为后端对象存储的角色,但不再使用其 POSIX 挂载能力,仅将其作为纯对象存储使用。这种方式规避了 SeaweedFS 在 POSIX 协议兼容性方面的不足,同时保持其在存储容量方面的优势。

训练任务中的缓存命中率提升方案

在采用分层存储架构后,如何在 BeeGFS 高速缓存与对象存储之间实现高效数据调度,成为影响训练性能的关键因素。随着多卡和分布式训练任务规模不断扩大,我们面临的不仅是带宽与容量的压力,更重要的是如何提升缓存命中率、减少冗余加载、加快训练启动速度等核心挑战。

为此,我们围绕"训练任务与数据访问行为"构建了一套完整的缓存命中优化机制,涵盖训练任务与数据集之间的自动关联建模、主动与被动相结合的预热策略,以及基于访问密度和历史行为的智能数据集优选逻辑。通过这些机制的协同,我们在有限的缓存资源下实现了高效的数据调度,优先加载高价值数据,显著提升了系统整体的资源利用效率与训练响应速度。

长期运行数据显示,系统缓存命中率稳定保持在 90% 以上,训练任务的读取性能基本可达 BeeGFS 水平的 80%,大幅优化了整体 I/O 效率和系统稳定性

策略1:构建训练任务与数据集的自动关联

为了更好地平衡 BeeGFS 与对象存储之间的资源利用率,我们希望尽可能提高缓存的命中率,从而减少对后端存储的重复访问。在此基础上,我们针对缓存预热策略进行了调度层面的优化。

具体做法是在训练任务创建流程中,增加了一个名为"加速"的参数选项。当工程师提交训练任务时,可以填写一个或多个压缩目录路径,作为本次训练所需的数据目录。系统会记录这些目录,并在后台周期性统计其历史使用频率和数据大小。目录的体积大小会作为预热调度的一个优先级参考因素,用于决定哪些数据应优先加载到共享缓存中。

通过这种方式,我们实现了训练任务与数据体系之间的关联,进一步提升了缓存层对热点数据的响应能力,从而提高整体训练任务的启动效率和 GPU 利用率。

策略2:结合主动与被动的缓存预热机制

为了提升整体缓存命中率,我们设计并实现了两种不同层次的缓存预热机制:被动预热与主动预热,分别适用于任务提交时的即时需求和系统空闲期的资源优化。

在被动预热场景中,当用户提交训练任务后,该任务会首先进入任务调度队列,等待 GPU 资源调度。与此同时,该任务所依赖的数据集会被送入预热调度队列,进行缓存预热的准备。为了避免重复加载,我们在预热队列中引入了去重机制,包括:多个任务使用相同数据集时的合并预热、上下级目录包含关系下的数据路径合并等处理。

在队列处理过程中,每个数据集会被赋予一个预热优先级,调度系统根据优先级依次执行预热操作。这意味着,训练任务的调度和其数据集的预热过程是异步进行的,二者调度系统相互独立。例如,在图示场景中,用户提交的是任务 A,但调度器可能此时优先调度运行任务 B,而预热系统此时却在执行数据集 C 的加载。被动预热的核心前提是:必须已有任务提交,才能触发数据集的预热流程。

与之对应,我们也设计了主动预热机制,用于在系统空闲时段(例如对象存储负载较低或训练业务处于低谷期)提前准备可能被使用的数据集。主动预热不依赖当前是否有任务排队,而是基于历史任务运行数据,自动识别出近期高频使用的数据集,并主动执行预热任务。通过在低负载时段执行这些任务,我们可以有效减少任务高峰时依赖被动预热的比例,从而提升整体训练效率,避免缓存穿透带来的性能波动。

通过主动与被动预热机制的结合,我们构建了一套兼顾资源效率与任务响应速度的智能缓存预热调度体系,有效提升了训练任务在共享缓存架构下的整体运行效率。

策略3:基于访问行为的数据集优选与命中率优化

在缓存预热过程中,多个待处理的数据集可能同时存在于预热队列中。为了合理安排执行顺序,我们制定了两项核心原则:

第一,尽量避免驱逐正在运行或即将排队运行的任务所依赖的数据集。为此,我们维护了一张缓存状态表,记录当前缓存中各数据集的存在情况及占用比例。如果某数据集已在缓存中占用空间较大,我们会暂停针对该集的新预热任务,避免低效的数据替换。

第二,优先选择历史命中率较高的数据集进行预热。具体而言,我们观察到部分工程师在填写训练任务的数据路径时,往往会填写上层较大的目录结构,而实际训练中只使用其中一部分子目录。如果盲目对整个目录进行预热,不仅会浪费存储资源,还可能导致有效数据被误驱逐。因此,我们引入了更加精细的分析机制。

我们利用任务平台记录的任务执行时间区间、节点分布等信息,结合 JuiceFS 提供的 metadata 监控能力,对每个数据集在任务执行期间的真实访问行为进行分析,统计实际读取的数据路径、读量及其在整个数据目录中的占比,进一步计算"缓存密度"与"命中率"。对于命中率高或在单个任务中被频繁访问的数据集,我们赋予更高的预热优先级。

新架构小结:实现大规模混合计算

通过对存储层和任务调度层的系统性改造,我们构建出一套支持大规模混合计算的统一基础设施。该架构能够灵活承载上层各类任务,包括 AI 训练与推理、大数据处理等不同类型的计算负载,底层则覆盖 CPU 与多类型 GPU 的异构计算资源。借助任务调度的灵活编排,实现不同任务类型在时间上的错峰运行,从而起到"削峰填谷"的作用,整体提升了资源利用率。

在存储层,我们实现了冷热数据分层管理机制,通过缓存加速与协议适配,满足训练过程中的高性能访问需求。同时,通过训练任务与数据集的自动关联建模、预热机制的调度优化,有效提升了系统在高并发场景下的响应速度与稳定性。 考虑到企业内部存在多种类型的训练任务,如 NLP、CV 等模型训练需求不一,我们将 JuiceFS 构建为一个统一的共享存储平台,为各部门提供稳定、高性能的分布式文件系统支持,保障了跨团队、大规模训练场景下的数据访问一致性与资源复用能力。

04 基于 JuiceFS 的冗余数据优化实践

避免新增重复文件

在系统运行一段时间后,我们发现一个普遍的使用场景:部分工程师习惯将公共数据集复制到个人目录下,进行修改后再执行训练任务。这种"拷贝再修改"的模式会导致大量冗余数据的产生,尤其是在多个用户对同一数据集进行轻微调整的场景下,整体存储成本迅速上升。

为了解决这一问题,我们引导用户使用 JuiceFS 提供的 juicefs clone 命令,该命令可以在文件系统层面实现快照式的数据复制,多个文件在逻辑上独立存在,但在底层对象存储中仍共享相同的数据块,从而显著降低存储空间的浪费。

这种机制依赖底层系统的支持,包括:

  • 使用 JuiceFS 原生命令进行克隆;
  • 操作系统内核需支持 copy_file_range;
  • 工具链中 cp 命令版本需不低于 8.3。

在早期阶段,由于未对这些前提条件进行强制要求,导致系统中出现了大量冗余数据副本。因此,我们启动了数据治理措施:一方面通过文档和训练引导工程师使用 juicefs clone 替代 cp;另一方面,我们对系统内核和 cp 工具版本进行了升级,以便透明地支持底层数据共享,从源头减少冗余写入的可能性。

清理存量重复文件

为进一步减少已存在的冗余数据,我们设计并实施了一套针对存量文件的重复检测与清理策略。具体方法如下:

首先,我们遍历整个 JuiceFS 文件系统,并按文件大小的"字节后缀"进行初步分区(例如所有文件大小以 10240 结尾的划为一组)。这样做的目的是将可能存在重复的数据文件归为同一类,减少不必要的比较计算。

在每个分区内,我们进一步筛选出大小相同的文件。接着,分两步进行内容相似度验证:

  • 快速前缀校验:优先比较文件的前 1KB 内容,作为快速过滤条件;
  • 全量字节比对:若前缀一致,再进一步对整文件内容做字节级比对,确认是否为完全相同的副本。

通过上述方法,我们成功识别出系统中约 10% 的文件存在重复内容。对于其中体积较大的冗余文件,我们优先使用 JuiceFS 提供的工具进行内容合并与去重,将其重定向为底层对象共享,回收冗余空间。

对于文件体积较小的重复项,由于去重处理成本可能高于收益,我们通常会选择保留。整体策略以"空间收益最大化"为原则,确保数据一致性前提下的安全清理。

随着公司内部大模型训练与推理需求的持续增长,原有存储架构在性能、容量与调度效率等方面逐步暴露出瓶颈。通过引入 JuiceFS 并结合任务调度、缓存预热与数据治理机制的持续优化,我们构建了一套具备良好可扩展性、稳定性和资源效率的训练数据存储体系。该体系已成功支撑公司内部多业务线、多类型任务的并发运行,为大规模 AI 基础设施建设奠定了坚实基础。后续我们将继续围绕训练场景的实际需求,迭代完善平台能力,进一步提升系统的智能化调度与资源调控能力,为内部 AI 应用提供更强支撑。

希望这篇内容能够对你有一些帮助,如果有其他疑问欢迎加入 JuiceFS 社区与大家共同交流。

相关推荐
间彧1 小时前
Spring Cloud Gateway与Kong或Nginx等API网关相比有哪些优劣势?
后端
间彧1 小时前
如何基于Spring Cloud Gateway实现灰度发布的具体配置示例?
后端
间彧1 小时前
在实际项目中如何设计一个高可用的Spring Cloud Gateway集群?
后端
间彧1 小时前
如何为Spring Cloud Gateway配置具体的负载均衡策略?
后端
间彧1 小时前
Spring Cloud Gateway详解与应用实战
后端
爱吃喵的鲤鱼1 小时前
仿mudou——Connection模块(连接管理)
linux·运维·服务器·开发语言·网络·c++
让子弹飞021 小时前
永久解决ubuntu网络连接问题
linux·运维·ubuntu
EnCi Zheng2 小时前
SpringBoot 配置文件完全指南-从入门到精通
java·spring boot·后端
烙印6012 小时前
Spring容器的心脏:深度解析refresh()方法(上)
java·后端·spring
Lisonseekpan3 小时前
Guava Cache 高性能本地缓存库详解与使用案例
java·spring boot·后端·缓存·guava