首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

大模型训练:K8s 环境中数千节点存储最佳实践

编程知识
2024年09月25日 14:30

今天这篇博客来自全栈工程师朱唯唯,她在前不久举办的 KubeCon 中国大会上进行了该主题分享。

Kubernetes 已经成为事实的应用编排标准,越来越多的应用在不断的向云原生靠拢。与此同时,人工智能技术的迅速发展,尤其是大型语言模型(LLM)的推进,导致企业需要处理的数据量急剧增加,例如,Llama 3.1 模型拥有 4050 亿参数,其模型文件的大小达到了 231GB。随着模型参数的增长,模型文件体积也随之增大。

01 Kuberenetes 中大模型训练的存储挑战

随着数据集群规模不断扩大,在 Kubernetes 环境中管理大规模数据集群面临多重挑战:

  1. 复杂权限管理:大规模 AI 训练往往涉及到上百人算法工程师,对文件系统的权限管理提出了复杂的需求。在 Kubernetes 环境中,这种规模的权限管理尤其困难,因为必须细粒度地控制对高度动态和分布式资源的访问,同时确保不影响开发和运维的效率。
  2. 稳定性挑战:在极致弹性的云原生环境中,文件系统的稳定性也面临了极大的挑战。如何保证重启或升级文件系统服务时,不影响业务?
  3. 系统可观测性:在复杂的 Kubernetes 系统下,如何增加系统可观测性,简化运维与问题排查的难度?

除了在 Kubernetes 环境中的挑战之外,存储系统还面临高并发、高吞吐量和低延迟的性能要求,以及在多云架构中维持数据一致性的挑战。

02 JuiceFS 的架构设计如何应对这些挑战?

JuiceFS 将元数据与数据分开存储。元数据存储在包括 Redis、MySQL 以及自研高性能云数据引擎等数据库中;而数据则被切分成块存储在对象存储中,支持市面上几乎所有类型的对象存储。这种将文件分块存储的方法使得所有文件的 I/O 请求都可以通过偏移量精确锁定到特定的块,特别适合大文件的读写操作,并确保数据一致性。

如下图所示,JuiceFS 客户端位于系统的上方,处理所有文件 I/O 请求,并向上层应用提供多种访问方式,包括 POSIX 接口、JuiceFS CSI Driver 和 S3 Gateway。

Kubernets 环境中的 JuiceFS

JuiceFS 提供了 CSI Driver,使用户可以在 Kubernetes 环境中通过原生的 Persistent Volume Claim (PVC) 方式使用文件系统,支持静态和动态配置。

在静态配置中,管理员为应用 Pod 创建一个单独的 Persistent Volume (PV)。用户只需创建一个 PVC,并在 Pod 中声明这个 PVC,即可在 Pod 中使用 JuiceFS。

动态配置则简化了管理员的工作。管理员无需为每个 Pod 单独创建 PV,而是创建一个 PV 的模板即 StorageClass。用户的操作与静态配置相同,仍需创建 PVC,系统将自动基于 StorageClass 动态生成所需的 PV。然后在运行当中系统会自动创建对应的 PV。

以下图解演示了当 JuiceFS CSI Driver 收到 Kubernetes 的挂载请求后的操作流程。系统会创建一个独立的 Pod 来运行 JuiceFS 客户端。这种设计带来了几个显著的好处:

  1. 增加系统稳定性和可扩展性:FUSE 客户端与 CSI Driver 组件进行了彻底的解耦,使得 CSI Driver 的重启和升级不会影响到 FUSE 客户端的运行。
  2. 便于管理 :此架构允许以 Kubernetes 的方式直观管理 FUSE 守护进程(daemon),增强了过程的透明性和管理效率。

Serverless 环境中如何运行 CSI Driver

在 Serverless 环境中,服务通常不与特定节点关联,这意味着无法在节点上运行守护进程(daemon site),从而使得 CSI node 组件无法正常工作。为解决这一问题,我们采用了创新性的解决方案,使用 Sidecar 模式,以支持 JuiceFS 在 Serverless 弹性环境中的运行,确保存储客户端的高可用性和灵活性。

具体操作中,我们在 CSI controller 中向 API server 注册了一个 webhook。当 API server 需要创建 Pod 时,它会向此 webhook 发起请求。通过这一机制,我们会向应用 Pod 注入一个 Sidecar 容器,在该容器中运行 JuiceFS 客户端。这种配置使得 JuiceFS 客户端能以 sidecar 的形式与应用容器共存于同一个 Pod 中,共享相同的生命周期,从而提高了整体的运行效率和稳定性。关于 Sidecar 模式,点击此处了解更多详情。

多租户环境中实现数据安全性

在多租户环境下,确保数据安全是一个重大挑战。JuiceFS 采用了多种安全机制来应对这一挑战:

数据隔离:通过为 StorageClass 动态声明的 PVC 分配不同的存储目录,JuiceFS 实现了不同业务间的数据隔离。

数据加密:在文件系统启动静态数据加密功能后,用户可以在 Secret 中设置密钥口令和密钥文件,从而启用 JuiceFS 的数据加密功能。

权限控制:用户可使用类 Unix 系统的 UID 和 GID 来管理文件权限,并可直接在 pod 中设置 uid 和 gid。此外,JuiceFS 还支持设置 POSIX ACL,以实现更细粒度的权限控制。

可无限扩展的存储空间

JuiceFS 是基于对象存储构建的,因此其实际上没有存储容量的上限。我们在对象存储的基础上实现了一套逻辑数据管理系统。

用户在使用时,可以在 PersistentVolumeClaim (PVC) 中通过指定 StorageClass 的属性值来设定 JuiceFS 的配额。这一过程类似于为 JuiceFS 设置一个容量配额。当需要进行数据扩容时,操作也非常简单:用户只需使用 kubectl 命令修改 PVC 中的 StorageClass 属性中的存储容量值,即可轻松实现数据的扩容。

如何实现高性能?

当大量客户端需要频繁访问相同的数据集时,分布式缓存能让多个客户端共享相同的缓存数据,显著提升性能。这种机制特别适用于使用 GPU 集群进行深度学习模型训练的场景。

以下是分布式缓存集群的一个典型部署方式。在 GPU 计算节点中,JuiceFS 客户端会运行,并使用本地的 NVMe 作为本地缓存。分布式文件缓存集群通常部署在近端,并通过预热方式从远端的对象存储中拉取数据到近端,供 GPU 节点上的客户端使用。

这里分享一项针对大文件顺序读和随机读的性能测试,以帮助大家理解分布式缓存的效果。如下图所示,在顺序读大文件的测试中,未启用缓存时带宽为 4.7GB,而启用缓存后带宽提升至 13.2GB。在随机读大文件的测试中,未使用缓存时的延迟为 29 毫秒,启用缓存后,延迟显著降低至 0.3毫秒 ,性能得到显著提升。

多云环境如何保持数据一致性?

随着模型参数和数据集规模的不断增大,公有云的 GPU 资源因其充足数量和高度灵活性而成为更合适的选择。为了降低成本并满足多云架构的需求,越来越多的公司选择在不同的云平台之间分配 GPU 资源。

我们引入了镜像文件系统功能,使用户能够在不同的云平台中访问 JuiceFS 数据,并保持数据的一致性。该系统通过异步方式将数据从原始文件系统同步到对象存储。

此外,我们通过元数据引擎定期同步 Raft 的 changelog 来增强数据一致性。在镜像文件系统中,客户端可对原始文件系统发起写请求,而读请求可从任一端发起——无论是原始文件系统还是镜像文件系统,均能确保数据的一致性。这种设计有效确保了多云架构中数据一致性的稳定性。

03 针对数千节点集群的实践与优化

在一个包含数千节点的集群中,最大的挑战之一是管理大量节点及其关联的资源,如Deployment、DaemonSet 等。随着这些资源请求的增多,APIServer 将面临极大的压力。

优化1:可视化监控

当集群中的资源众多时,故障排查往往变得繁琐且困难。为此,我们提供了一套可视化的dashboard。在这个 dashboard 中,我们可以列出所有使用 JuiceFS PVC 的应用 Pod,并显示每个 Pod 对应的挂载 Pod 以及它们的运行状态。

此外,如果应用 Pod 出现异常,dashboard 还会展示一些 tips,说明可能的具体原因,以便为用户提供进一步的排查方向。这套 dashboard 极大地简化了用户的故障排查过程,点击此处了解该功能详情。

优化2:资源 & 性能

对于应用 Pod,为每个 Pod 单独创建挂载点是不现实且浪费资源的。因此,所有使用同一 PersistentVolumeClaim (PVC) 的应用 Pods 默认会共享一个挂载 Pod,并且在某些配置下,所有使用同一 StorageClass 的应用 Pods 也将共享一个挂载 Pod,以进一步优化资源使用。

另一方面,CSI 管理挂载 Pod 生命周期时采用了 list-watch 的方法。在大规模集群中,CSI 组件启动时的全量 list 请求会对 API server 造成极大压力,甚至有可能导致其宕机。因此,我们采取的策略是每个节点上的 CSI 组件会单独轮询对应节点的 Kubelet,从而减轻对 API server 的压力。

优化3:稳定性

由于 FUSE 客户端的特殊性,在重启后其挂载点可能仍然无法使用,这会影响所有应用端的数据请求。为此,我们之前进行了一项优化:当 Mount Pod 因 OOM 或其他原因重启时,我们会在 CSI 中为应用 Pod 执行重新挂载。虽然这种方式能够恢复挂载点,但文件请求在当时仍可能受到影响。

为了进一步优化,我们在 Mount Pod 启动时从 /devfuse 中获取它使用的 fuse 文件描述符(fd),并将此 fd 通过进程间通信(IPC)直接传递给 CSI Driver。CSI Driver 会在内存中维护 Mount Pod 和它所使用的 fuse fd 的映射关系。如果 Mount Pod 因 OOM 重启,CSI 会立即将其删除,并启动一个新的 Pod 来替代它。

这个新的 Pod 启动后,会通过 IPC 从 CSI 获取之前使用的 fuse fd,并重新处理业务请求。这种方式对用户端的影响相对较小,在读文件操作中只会出现短暂的卡顿,不会影响后续的处理。

优化4:平滑升级

Mount Pod 的平滑升级与之前提到的故障恢复相似,但有一个显著区别,在原有的升级过程中,旧的客户端会将其当前处理的所有数据请求保存到一个临时文件中。实现平滑升级功能后,新的客户端将执行两个操作:一是从 CSI 获取其 fuse 文件描述符(fd),二是在启动后立即从该临时文件中读取升级前的数据请求。这样做能确保在升级过程中不会遗漏任何业务请求,从而实现真正的平滑升级功能。

04 总结

自 2021 年 7 月 JuiceFS CSI Driver 首次推出以来,随着 Kubernetes 用户数量的增长和集群规模的不断扩大,面对的应用场景也愈发复杂。过去三年多的时间里,我们对 JuiceFS CSI Driver 在稳定性、管理权限等关键领域进行了持续的优化和改进,这使得 JuiceFS 能够有效地适应各种复杂的需求,成为 Kubernetes 环境中数据持久化的理想选择。

最后,我们将再次概述 JuiceFS 的核心特性以及关键优化,以帮助用户在 Kubernetes 环境中更好地进行存储选型。

  • 数据安全:JuiceFS 通过实行数据隔离、加密和权限控制来保障数据安全。此外,其分布式缓存技术不仅提升了系统性能,还有效地控制了成本。
  • 数据弹性:在 Serverless 环境中,JuiceFS 采用 sidecar 设计模式和动态数据扩容技术,以增强数据弹性。
  • 数据一致性:JuiceFS 的镜像文件系统功能保证了多云架构下的数据一致性,确保了数据在不同云平台间的稳定性和可靠性。
  • 高性能与成本控制:JuiceFS 支持从对象存储中快速将必要文件数据拉取到本地缓存,这一过程通常在 10 到 20 秒内完成,大幅缩短了数据获取时间,相较于无缓存状态下的四至五百秒。预热过程采用并行处理方式,能在模型加载前完成,有效减少了启动时间。
  • POSIX 兼容性:JuiceFS 提供全面的 POSIX 兼容性,确保与多种应用和系统的高度兼容性。
From:https://www.cnblogs.com/JuiceData/p/18431452
本文地址: http://www.shuzixingkong.net/article/2297
0评论
提交 加载更多评论
其他文章 Python计算傅里叶变换
本文介绍了离散傅里叶变换和快速傅里叶变换的基本原理及其对应的Python代码实现,并将计算结果与numpy所集成的fft函数进行对比。其实现在FFT计算的成熟工具已经有很多了,不论是CPU上scipy的fft模块还是GPU上的cufft动态链接库,都有非常好的性能。但还是得真正去了解计算背后的原理,
Python计算傅里叶变换 Python计算傅里叶变换
.net 到底行不行!2000 人在线的客服系统真实屏录演示(附技术详解) 📹
时常有朋友问我性能方面的问题,正好有一个真实客户,在线的访客数量达到了 2000 人。在争得客户同意后,我录了一个视频。升讯威在线客服系统可以在极低配置的服务器环境下,轻松应对这种情况,依然可以做到消息毫秒级送达,操作毫秒级响应。
.net 到底行不行!2000 人在线的客服系统真实屏录演示(附技术详解) 📹 .net 到底行不行!2000 人在线的客服系统真实屏录演示(附技术详解) 📹 .net 到底行不行!2000 人在线的客服系统真实屏录演示(附技术详解) 📹
SimpleAIAgent:使用免费的glm-4-flash即可开始构建简单的AI Agent应用
SimpleAIAgent是基于C# Semantic Kernel 与 WPF构建的一款AI Agent探索应用。主要用于使用国产大语言模型或开源大语言模型构建AI Agent应用的探索学习,希望能够帮助到感兴趣的朋友。 接下来我想分享一下我的AI Agent应用实践。 翻译文本并将文本存入文件
SimpleAIAgent:使用免费的glm-4-flash即可开始构建简单的AI Agent应用 SimpleAIAgent:使用免费的glm-4-flash即可开始构建简单的AI Agent应用 SimpleAIAgent:使用免费的glm-4-flash即可开始构建简单的AI Agent应用
这才是批量update的正确姿势!
前言 最近我有位小伙伴问我,在实际工作中,批量更新的代码要怎么写。 这个问题挺有代表性的,今天拿出来给大家一起分享一下,希望对你会有所帮助。 1 案发现场 有一天上午,在我的知识星球群里,有位小伙伴问了我一个问题:批量更新你们一般是使用when case吗?还是有其他的批量更新方法? 我的回答是:咱
这才是批量update的正确姿势!
树形结构工具类
前言 日常开发中,树形结构的数据是比较常见的一种数据结构,比如系统菜单、组织机构、数据字典等,有时候需要后端把数据转成树形结构再返回给前端,对此特意封装通用树形结构工具类 封装了以下方法: 根据父id,递归获取所有子节点,转为树结构 根据子id,递归获取所有父节点,转为树结构 拼接 union sq
树形结构工具类 树形结构工具类 树形结构工具类
裁员,这一次终于轮到了我
新产品发行失利,流水逐渐下滑,裁员成了公司不可避免的选择,看着身边朝夕相处的同事一个个离开,甚至还要亲自去跟团队内的同事谈离职,真的很不是滋味。好在这一切即将结束,我也要走了,公司给了足额的赔偿,我觉得挺好,于我而言,这是最好的结果。公司如果赚钱,即便不会多发给我,那我也是干劲十足,我会觉得我的工作
Rust字符串类型全解析
字符串是每种编程语言都绕不开的类型, 不过,在Rust中,你会看到远比其他语言更加丰富多样的字符串类型。 如下图: 为什么Rust中需要这么多种表示字符串的类型呢? 初学Rust时,可能无法理解为什么要这样设计?为什么要给使用字符串带来这么多不必要的复杂性? 其实,Rust中对于字符串的设计,优先考
Rust字符串类型全解析 Rust字符串类型全解析 Rust字符串类型全解析
面试官:谈谈你对 IoC 和 AOP 的理解!
本文摘录自笔者开源的 Java 学习&面试指南(Github 收获146k star):JavaGuide 。 这篇文章会从下面从以下几个问题展开对 IoC & AOP 的解释 什么是 IoC? IoC 解决了什么问题? IoC 和 DI 的区别? 什么是 AOP? AOP 解决了什
面试官:谈谈你对 IoC 和 AOP 的理解! 面试官:谈谈你对 IoC 和 AOP 的理解! 面试官:谈谈你对 IoC 和 AOP 的理解!