Lepton AI 是一款面向开发者的 AI 平台,旨在提供易用、高效且可扩展的基础设施能力。该平台适用于各种训练、推理需求,GPU充足,在保证高性能的同时,能够灵活应对不断变化的工作负载。用户可以快速在 Lepton 平台上部署推理服务和执行训练任务,无需关注基础设施和稳定性问题。

作为一家初创公司,Lepton AI 致力于在云端为企业提供领先的 AI 推理与训练技术,而在存储这类基础设施建设,希望能够在市场上找到合适的供应商,以保障更高效的产品研发。JuiceFS 非常契合 Lepton AI 的需求。基于 JuiceFS,Lepton AI 利用其高性能的缓存机制显著加速了文件操作,显著降低了由于对象存储引发的延迟问题,并与此前使用的 AWS EFS 相比,存储成本降低了 30 到 50 分之一。
JuiceFS 最近增加的新特性,按需读取对象存储上已有数据并进行缓存,使得 Lepton 可以不用预先从客户的已有存储复制数据,更加提高了 JuiceFS 的可用性。目前,Lepton AI 在 JuiceFS 上存储的文件规模已达到数十亿个文件,同时 JuiceFS 的性能表现也非常优秀,满足了系统对高吞吐量和低延迟的要求
01 Lepton AI 平台的存储需求
Lepton AI 平台的用户数据主要分为三类:
- 训练数据,例如大量的图片。这些数据主要是只读的,在训练过程中,我们会从中读取一部分数据进行模型训练。
- 快照数据(Snapshot),用户在训练过程中会定期保存一些中间结果,以便在出现故障时能够从之前的快照继续训练。例如,若在训练过程中出现 GPU 故障,用户可以从最近的快照恢复并继续训练。此类数据通常是只写的,只有在保存快照时进行写入,读取则较为有限。
- 训练出来的模型数据,这些模型在训练完成后主要是读取,完成写入操作后一般不会进行修改,因此这类数据也是以写为主,读取较为频繁,但修改操作较少。
针对以上这些需求,对存储系统提出的挑战如下:
应对不稳定的 GPU :Lepton 的客户主要使用 H100 GPU,但这一型号的 GPU 存在较大的不稳定性。GPU 出现故障后,需要将整台机器下线进行修复,无论是更换 GPU 卡还是更换与 GPU 相关的其他组件。修复过程中,机器无法访问磁盘,因此无法像传统的分布式存储系统那样简单地进行数据存储。这会导致大量数据的移动和备份问题,增加了数据丢失的风险。
数据迁移问题:我们服务的很多客户会直接要求迁移大量数据到我们的系统。然而,直接将海量数据复制到我们平台并不现实,尤其是当客户有成千上亿个小文件时。例如,我们曾有一个客户,文件数量高达数十亿个,文件复制速度非常缓慢。由于这种数据迁移的高耗时,我们无法要求客户先完成数据迁移再开始使用我们的平台。实际上,很多客户更倾向于先试用平台,确认其效果后再决定是否进行全面的数据迁移。
多租户问题:在多租户环境下,客户的 GPU 分布在不同的位置和数据中心。我们在美东、美西以及欧洲等地区均有数据中心,这导致不同区域之间的延迟较大。如果使用传统的大型文件系统,这将使得多租户管理变得尤为复杂。需要解决的数据隔离、访问控制和延迟问题,增加了存储系统的设计复杂性。
数十亿小文件的读写性能问题:存储大量小文件时,读写性能会受到严重影响。由于每个小文件的访问时间较短,存储系统需要处理大量的文件操作,这会大大降低整体的读写效率。因此,如何高效处理数十亿小文件的存储和访问,成为系统设计中的一大挑战。
02 存储架构设计与选型
存储架构设计
为了解决这些问题,我们理想中的存储架构是这样的:
-
云存储与本地缓存结合:我们将数据存储在云端,使用本地磁盘作为分布式缓存。这样可以避免 GPU 故障导致的磁盘不可读问题,并提升系统的整体稳定性与性能。
-
支持多租户环境:为每个客户创建独立的文件系统,允许在各自的文件系统中调整性能,简化安全性管理。由于每个文件系统对应一个独立的用户,彼此无法访问,安全性得到保障。
-
提高读性能:本地磁盘作为分布式缓存,提高读性能。
-
POSIX API 兼容性:我们需要 POSIX API,以便用户的代码无需迁移,可以直接在我们的平台上读取数据。
我们评估了现有的开源系统及一些服务商,最终发现 JuiceFS 完全符合我们的需求,而且 JuiceFS 的表现稳定,价格也非常合理。
费用比较:AWS EFS vs JuiceFS
我们最初尝试过 AWS EFS,并对比了 EFS 与 JuiceFS 的价格。存储方面,JuiceFS 将数据存储到 object store 中,价格大约是 EFS 的十分之一,明显更便宜。至于数据传输,EFS 在 AWS 内部有固定费用,而数据出 AWS 则另行收费。但随着规模的扩大,我们的大部分 GPU 并不在 AWS 中,而是外部租用的数据中心中。因此,EFS 的数据进出费用变得非常昂贵。
相比之下,使用 JuiceFS 让我们可以自主选择后端对象存储。我们选择了 Backblaze 和 Cloudflare,它们不收取数据传输费用,因此整体成本是使用 EFS 的30 到 50 分之一。
03 在 Kubernetes 中使用 JuiceFS 的实践技巧
分布式缓存:CSI 还是 HostPath?
我们最初使用 JuiceFS 时遇到的第一个问题是,JuiceFS 支持两种设置方式:CSI 和 HostPath。为了处理分布式缓存问题,如果使用 CSI,客户端将运行在 Kubernetes 的 pod 中,并且当 pod 生命周期结束时,缓存的数据将无法读取。因此,我们认为使用 HostPath 更为合适。
我们选择将 JuiceFS 挂载到 GPU 机器的某个路径上,并设置分布式缓存。这样,当 Kubernetes 启动 pod 时,Pod 可以直接挂载该路径并访问 JuiceFS 中的数据。与此同时,我们在启动 pod 时也为多租户环境做了一些隔离措施。
(编者注:JuiceFS 已开发了 JuiceFS Operator ,可在 K8s 集群中独立部署分布式缓存集群。)
JuiceFS 如何挂载到主机上?
我们的做法是在 Kubernetes 中创建了一个 CRD,叫做 LeptonNodeGroup。这个 NodeGroup 是一个 GPU 集群,与 Kubernetes 集群不同,它的功能相对较小。例如,一个客户在我们的平台上租用了 1000 张 GPU 卡,这 1000 张卡位于同一个数据中心。我们会为这 1000 张卡创建一个单独的 CR,其中存储了这些 GPU 的配置,包括 JuiceFS 的相关配置。
我们使用了一个 DaemonSet 来挂载 JuiceFS。这个 DaemonSet 中的每个 Pod 都运行在特权模式下,它会监视 LeptonNodeGroup。当发现该 LeptonNodeGroup 中的 JuiceFS 配置发生变化时,Pod 会通过 setns 系统调用进入到节点的命名空间,并通过 systemd 来挂载 JuiceFS。我们已经运行了这个方案超过一年,结果表明系统稳定且易于使用,整体表现良好,除了少数小问题外。
数十亿小文件处理
如前所述,我们需要处理大量的小文件,其中有几个客户提供了几十亿个小文件。虽然我们知道使用大文件会更高效,但客户的需求使得我们不得不处理这些小文件,且我们无法选择客户的数据格式。经过测试,我们发现如果直接将这些文件复制到 JuiceFS 中,几乎不可能在合理的时间内完成。
JuiceFS 提供了一个导入功能,能够直接从客户原先存储在 S3 上的小文件中导入数据,速度非常快。然而,对于处理几十亿个文件来说,这个速度仍然不够快。在 S3 中,文件名的导入过程可能需要一天时间,尽管通过一些优化手段,时间可以缩短至大约十个小时。如果不进行任何优化,整个过程可能需要 3 到 5 天。
为了解决这个问题,我们尽量将 JuiceFS 的元数据服务与我们的 GPU 机器部署在同一数据中心,以减少延迟。我们花了一些时间来解决 GPU 机器的不稳定问题,因为我们无法在自己的集群中仅依赖 CPU 机器,所以选择从其他厂商租赁机器,并通过调整网络拓扑,最终在同一数据中心找到了合适的机器。虽然这些机器不是通过内网连接,但性能和延迟仍然非常低,能够满足需求。
此外,在与 JuiceFS 团队的讨论后,他们实现了 lazy load 功能,使得在导入文件时,不需要先将所有文件和元数据加载进来就可以直接使用。这个功能是最近几个月才推出的,我们还没有对其进行详细测试,但初步感觉它能够有效地提升效率。
性能表现
我们公司已经使用 JuiceFS 一年多了,整体使用效果不错,虽然我们没有进行详细的性能测试,但客户的反馈比较满意。我们测试性能使用的 GPU 集群有 32 个节点,每个节点配备 8 张 H100 卡,共计 256 张卡。
在单台机器上读取数据时,性能大约可以达到 2 GB/s。这个性能主要受限于机器的带宽,我们的带宽为 40 Gbps,但还跑了一些其他任务,因此实际速度为 2 GB/s 左右。
在延迟方面,P99 延迟通常控制在 10 毫秒以内,平均延迟大约为 3 到 5 毫秒,因为访问元数据服务器时会增加约 2 毫秒的延迟。对于训练来说,这个延迟基本上是可以接受的,用户可以顺利地进行数据读取。
写入性能方面,能够达到 1 GB/s,但有时会受到对象存储延迟和吞吐量的限制。
03 未来计划
我们计划继续优化存储流程,进一步自动化现有的操作,以支持更多的多租户用户。目前,一部分流程已经实现了自动化,但仍有一些操作是手动完成的。例如,创建对象存储的 bucket 目前是手动完成的,而在 JuiceFS 中的文件系统创建过程中,有些步骤已经实现了自动化。我们还需要进一步完善自动化流程。
另外,使用 JuiceFS 后,我们面临分布式缓存稳定性的问题。由于 GPU 故障需要下线修复,这会导致数据需要进行重新平衡。为了避免数据重新平衡,我们需要将数据存储为多个副本。但存储多份数据会占用更多的磁盘空间,且有时可能导致空间不足。如何解决这个问题,目前我们还在探索中。