网站建设在那里接单,给个网址谢谢了,wordpress 微信,湖南省建设厅官方网站随着大模型流行#xff0c;GPU 算力资源正变得日益稀缺#xff0c;传统的“算力跟着存储跑”的策略需要转变为“存储跟着算力跑”。为了确保数据一致性和管理的便捷性#xff0c;企业通常在特定地区的公有云上选择对象存储作为所有模型数据的集中存储点。当进行计算任务调度…随着大模型流行GPU 算力资源正变得日益稀缺传统的“算力跟着存储跑”的策略需要转变为“存储跟着算力跑”。为了确保数据一致性和管理的便捷性企业通常在特定地区的公有云上选择对象存储作为所有模型数据的集中存储点。当进行计算任务调度时往往需要人工介入手动进行数据拷贝和迁移方法不仅成本高昂还存在管理和维护的复杂性包括权限控制等问题都极为棘手。
JuiceFS 企业版的 “镜像文件系统” 功能允许用户从一个地区自动复制元数据到多个地区形成一对多的复制模式。在多云架构下该功能在确保数据一致性的同时大幅降低人工运维的工作量。
最新的 JuiceFS 企业版 5.1 中 镜像文件系统除了支持读取还新增了可直接写入的功能。本文将探讨镜像文件系统的读写实现原理。
01 为什么需要镜像文件系统
让我们设想这样一个场景某用户的文件系统部署在北京但北京地区的 GPU 资源供给不足而该用户在上海还有可用的 GPU 资源。这时用户想在上海运行模型训练任务有两个简单的方案
直接在上海挂载北京的文件系统。理论上来说只要北京与上海之间的网络连接顺畅上海的客户端确实就能访问数据以进行训练。然而实际情况是文件系统的访问通常涉及到频繁的元数据操作而由于两地的网络延迟较大性能结果往往都无法达到预期。在上海建立新的文件系统在训练前拷贝所需数据集到上海。这样做的优点是可以保证上海训练任务的性能。但缺点也是很明显的一方面构建新文件系统需要较高的硬件成本另一方面每次训练前同步数据也提高了运维的复杂性。
综上所述这两个简单的方案都无法令人满意。为此 JuiceFS 企业版提供了镜像文件系统功能。它允许用户为已有文件系统创建一个或多个完整的镜像这些镜像会自动从源端同步元数据这样在镜像区域的客户端可以就近访问文件系统来得到高性能的体验。由于可以只镜像元数据并且同步过程是自动的因此相较于之前提到的方案二而言镜像文件系统在成本与运维复杂性上都有明显的优势。
02 镜像文件系统原理
JuiceFS 企业版的架构与社区版相似都包括客户端、对象存储以及元数据引擎。区别在于社区版的元数据引擎通常采用第三方数据库如 Redis、TiKV、MySQL 等而企业版则配备了自研的高性能元数据服务其中的元数据引擎由一个或多个 Raft 组组成其架构图如下 得益于元数据与数据分离的架构设计用户在创建镜像文件系统时可以独立选择是否镜像元数据和是否镜像数据。两者皆配置镜像的架构如下 此时镜像的元数据服务其实跟源端的元数据服务同属一个 Raft 组只是它们的角色是 learner。在源端发生元数据更新时服务会自动推送变更日志到镜像端并在镜像服务中进行回放。这样镜像文件系统的存在并不会影响源端文件系统的性能表现只是镜像的元数据版本会略落后一点点。
数据的镜像也是采用异步复制的方式由指定配置的节点进行自动同步。不同的是对镜像区域的客户端而言它仅访问本区域的元数据但是可以同时访问两个区域的对象存储。实际读取数据时客户端优先从本区域读取如果查找不到所需的对象再尝试从源端区域读取。
一般而言数据本身的体量较大再拷贝一份的成本也比较高因此另一种更推荐的方式是仅镜像元数据并且在镜像区域构建一套分布式缓存组来提升读取数据的速度示意如下 JuiceFS 镜像文件系统推荐使用方法两区域共用同一个对象存储镜像区域搭建分布式缓存组来提升性能
这种使用方式尤其适合模型训练等可以提前准备数据集的场景。用户在执行训练任务前先通过 juicefs warmup 命令将所需数据对象拉取到镜像区域的缓存组中接下来的训练就能在镜像区域内完成且性能与在源端假设也配置了类似的分布式缓存组基本一致。
03 实验性新功能可写镜像文件系统
在之前的版本中镜像客户端默认为只读模式因为镜像元数据本身只支持读取所有的修改操作必须在源端执行。然而随着用户需求的增加我们注意到一些新的使用情况例如在数据训练过程中产生的临时数据。用户希望避免维护两个不同的文件系统并期望镜像端也能支持少量写操作。
为了满足这些需求我们在 5.1 版本中引入了 “可写镜像文件系统” 功能。在设计这项功能时我们主要考虑三个方面首先是系统的稳定性这是必须保证的其次是两端数据的一致性最后是写入的性能。 最初我们探索的一种直接方案是允许元数据镜像也能处理写操作。然而在开发中我们发现当需要将两端的元数据更新进行合并时会面临非常复杂的细节处理和一致性问题。因此我们还是维持 “仅源端元数据可写” 的设计。为了处理镜像客户端的写请求有两个可选的方案
方案一客户端将写请求发送至镜像的元数据服务然后由其转发到源端。源端接收到请求后开始执行操作并在完成后将元数据同步回镜像端并最终返回。这个方法的优点是客户端操作简单只需发送请求并等待响应。然而这样会使元数据服务的实现变得复杂因为需要管理请求的转发和元数据的同步。此外由于链路较长任何环节的错误都可能导致请求处理出错。
方案二客户端不仅连接镜像的元数据服务还直接连接源端的元数据服务。客户端内部进行读写分离读请求仍然发送至镜像端但将写请求发送至源端。这种方法虽然使客户端的处理逻辑复杂化但简化了元数据服务的实现让它们仅需做很小的适配改动即可。对整个系统而言这样的做法稳定性也更高。
考虑到服务的简洁性和可靠性我们最终选择了方案二具体如下图所示。相较于原来的架构而言这个方案主要多了一条镜像客户端发送写请求到源端元数据服务的流程。 以下将以创建一个新文件create 请求为例对此流程进行详细的介绍。假设源端和镜像端的元数据服务分别是 A 和 B镜像客户端为 C请求的完成大致分为 5 步 客户端发送写请求C 首先将创建文件的 create 请求发送至 A。源端服务响应A 在处理请求后发送 create OK 告知 C 文件已成功创建并在响应中附带 A 的元数据版本号假设为 v1。变更日志推送A 在发送回复给客户端的同时也会立即生成一条变更日志并将其推送给 B。客户端发送等待请求C 接收到源端的成功回复后会检查自己的镜像元数据缓存看其版本是否也达到了 v1。如果没有客户端会发送一条 wait 消息给 B并附上版本号 v1。镜像端服务响应B 收到等待消息后检查自己的元数据版本。如果已经达到 v1则立即回复 wait OK 给 C否则的话就将请求放入内部队列等自己的版本号更新到 v1 以后再发送回复。
C 在第 4 步确认镜像版本已经达到 v1或者第 5 步收到 wait OK 后返回给上层应用。无论哪种情况都表示 B 已经包含了本次 create 的修改因此后续 C 在读取时就能访问到最新的元数据。另外由于步骤 2 和 3 几乎是同时发生的所以大部分情况下 wait 消息都能被立即处理并返回。
镜像客户端的读操作也有类似的检查版本的机制。具体而言C 在发送读请求前会先比较其缓存中源端服务和镜像端服务的元数据版本号如果源端的版本号更新则会先发送 wait 消息给 B等到其版本也更新上来后再处理原来的读请求。遗憾的是C 缓存的源端版本号并不一定是最新的比如其长时间未发送过写请求的情况也就是说该机制只是尽可能地让 C 能读到较新的数据但并不保证其一定是最新的可能会有小于 1 秒的滞后与原有的只读镜像相同。
最后我们通过一个稍复杂些的读写混合的例子来简要说明使用 JuiceFS 镜像文件系统给用户带来的直接收益。
需求是客户端 C 希望在 /d1/d2/d3/d4 目录下创建一个新文件 newf。按照文件系统的设计C 需要逐级查找路径上的每一个目录和文件并在确认文件不存在后再发送创建请求。现假设 C 到 A 和 B 的网络延迟分别是 30ms 和 1msC 尚未建立元数据缓存并且忽略 A 和 B 的请求处理时间。
使用镜像文件系统的情况C 的读请求都由 B 处理只有最后的创建文件请求需要发往 A。总耗时大概需要 1 * 2 * 6(mirror lookup) 30 * 2(source create) 1 * 2(mirror wait) 74ms。
没有使用镜像文件系统的情况如果直接在镜像区域挂载源文件系统C 的每个请求都需要跟 A 交互那么总耗时就需要 30 * 2 * 6(source lookup) 30 * 2(source create) 420ms是前者的 5 倍还多。
04 小结
在 AI 研究中由于 GPU 资源的成本极高多云架构已成为众多企业的标配。通过使用 JuiceFS 镜像文件系统用户可创建一个或多个完整的文件系统镜像这些镜像会自动从源端同步元数据使得镜像区域的客户端能够就近访问文件从而提供高性能并减少运维工作量。
在最新的 JuiceFS 5.1 版本中我们对镜像文件系统进行了重要的优化新增了允许写入的功能使得企业能够在任何数据中心通过统一的命名空间访问数据。同时在保证数据一致性的前提下享受就近缓存的加速效果。希望通过这篇文章分享的实现思路与尝试为用户提供一些见解与启发。