基于 JuiceFS 构建高校 AI 存储方案:高并发、系统稳定、运维简单

中山大学的 iSEE 实验室(Intelligence Science and System) Lab)在进行深度学习任务时,需要处理大量小文件读取。在高并发读写场景下,原先使用的 NFS 性能较低,常在高峰期导致数据节点卡死。此外,NFS 系统的单点故障问题也导致一旦数据节点宕机,该机器上的数据将完全不可用。扩容问题同样棘手,每增加一台数据节点,就需要在所有计算节点上进行多次挂载。而新增的数据节点由于数据量较小,并不能有效分担读写压力。

为解决这些问题,经过初步评估,实验室选择了JuiceFS 作为替代的存储方案。当前,结合TiKV 的 JuiceFS 已成功管理超过 5 亿个文件。新方案显著提升了在高并发场景下的性能和系统稳定性,确保了深度学习训练过程中计算节点的连续运行,同时基本解决了单点故障的问题。

此外,JuiceFS 的操作简便易学,甚至不需要专职的存储管理人员来维护,这对于主要由 AI 领域学生组成的实验室集群管理团队来说,极大减轻了他们的运维负担。本文将详细介绍新方案的选型与实践历程。

01 深度学习场景存储需求

实验室集群主要用于深度学习的训练和方法验证。在训练过程中,我们面临四种主要的读写需求。

  1. 训练过程中需要读取大量的数据集文件。

  2. 在模型训练的初始阶段,我们需要加载一个 Conda 的环境,这涉及读取众多不同大小的库文件。

  3. 在训练过程中,随着模型参数的调整,我们需要频繁地写入不同大小的模型参数切换文件,这些文件的大小可能从几十兆字节到数几字节不等,具体取决于模型的大小。

  4. 我们还需要记录(每次训练的)训练日志,这主要涉及到少量数据的频繁写入。

基于上述需求,我们对存储系统有以下四个主要期望:

  • **首要的是,系统在高并发的读写环境下应具备出色的稳定性。**在确保稳定性的基础上,我们再追求性能的提升。

  • 其次,我们希望系统能够消除单点故障,即任何节点的故障都不应影响整个集群的训练进程。

  • 第三,我们期望系统具有友好的运维特性。考虑到我们实验室团队成员主要专注于 AI 深度学习,对存储系统的专业知识了解有限,因此我们需要一个运维简便、维护频率较低的存储系统。

  • 最后,我们希望系统能够提供一个 POSIX 接口。由于我们使用 PyTorch 框架进行模型训练,如果系统支持 POSIX 接口,将极大地降低用户的学习成本,同时减少对现有代码的改动。

实验室现有的硬件配置

首先,我们的硬件系统主要包括三类设备。

第一类是数据节点,我们目前拥有大约三四台这样的数据节点。这些节点主要由大量机械硬盘构成,每个节点的机械硬盘都搭建RAID6阵列,所有节点加起来的总存储容量近 700TB。

第二类是我们的计算节点,这些节点主要搭载了 GPU,用于处理计算密集型任务。在存储方面,由于 JuiceFS 具有缓存功能,我们为这些节点配备了 1 至 3 个 SSD 缓存盘,每个盘的大小约为 800GB。尽管这些缓存盘的大小看起来并不庞大,但它们通常能够缓存多个完整的数据集,前提是数据集的大小适中。

第三类是基于我们使用 TiKV 作为元数据引擎的考量,我们配置了三个 TiKV 节点,专门用于作为元数据引擎运行。这些节点的数据盘容量大约为 2TB,内存则主要配置了 512GB。根据目前的使用情况,当处理大约 5 至 6 亿的文件量时,每台节点大约使用了 300 多 GB 的内存。

NFS 的存储解决方案所面临的挑战

在初期,当计算节点数量较少时,我们采用了在数据节点上构建单机文件系统的策略,并通过简单的 NFS 挂载方式,将这些文件系统挂载到各个计算节点的目录上。这样,当需要添加第二台数据节点时,我们只需将其挂载到新的目录上,即可实现数据在所有节点间的共享。此方案在运维上相对简单,但随着节点数量的增加,我们逐渐发现基于 NFS 的存储系统性能显著下降。

在高并发训练高峰期,系统常出现明显的卡顿甚至卡死现象,这极大地影响了我们的工作效率。为了缓解这一问题,我们曾尝试将集群划分为两个小集群,以减少每个节点的数据压力。然而,这一临时措施并未带来显著的改进,反而带来了新的问题,如不同集群间数据的互通性受限。

总的来说,我们在处理大量小文件读取的场景下,原有的 NFS 存储方案表现出了较低的读取性能和较高的宕机风险。此外,整个系统缺乏缓存机制,而深度学习数据集在训练过程中需要频繁读取,这无疑增加了读写压力。因此,我们需要寻找一种更为高效、稳定的存储解决方案,以应对这些挑战。

02 为何选择 JuiceFS

以下是我们选择 JuiceFS 的主要原因:

  • JuiceFS 支持 POSIX 接口,这意味着在迁移系统时,用户几乎不会感受到任何影响,实现了无感的迁移体验。

  • JuiceFS 的缓存功能对于深度学习模型的训练尤为重要。尽管在首轮数据加载时可能无法直接命中缓存,但随着训练的进行,后续轮次几乎能够百分之百地利用缓存,从而显著提升训练过程中的数据读取速度。

  • JuiceFS 的回收站功能为用户提供了数据恢复的可能性,我们设置的为期一天的回收站使得误删的文件在一天内得以恢复,这在实际应用中已帮助用户及时恢复了误删的数据。

  • JuiceFS 还配备了一系列特有的文件管理命令,这些命令不仅方便用户使用,而且相较于传统文件系统,其功能更为快速和高效。

  • 值得一提的是,在运维层面,JuiceFS 的表现格外出色。由于我们实验室没有专职的人员负责存储,我们期望的存储系统应具备简单性和低运维频率的特点,而 JuiceFS 恰好满足了这些需求。它提供了丰富的文档资源,使得我们在上手和解决问题时能够迅速找到解决方案。JuiceFS 能够自动备份元数据,为数据提供了额外的保护层,增强了我们的安全感。JuiceFS 自带的 Prometheus 和 Grafana 监控功能使得我们能够方便地在网页端查看整个系统的状态,包括文件数量的增长情况、文件使用量以及整个系统的大小等关键信息,这为我们提供了及时的系统监控和管理的便利。

03 搭建基于 JuiceFS 的存储系统

首先,我们的 JuiceFS 采用了 TiKV 作为元数据引擎,同时利用 SeaweedFS 作为对象存储。

总体来看,JuiceFS 分为两个目录进行挂载。第一个目录用于存储用户文件,采用独立挂载的方式使我们能够灵活调整挂载参数,以满足不同目录的特定需求。在用户文件目录方面,我们主要沿用了默认的挂载参数,以确保稳定性和兼容性。

第二个在数据集目录方面,鉴于其几乎只读的特性,我们特别增加了元数据缓存的失效时间。这样做可以在多次读取过程中多次命中元数据缓存,从而避免重复访问原始数据,显著提升数据访问的速度。正是基于这一改动,我们选择了将数据集和用户文件分别挂载于两个不同的目录。

此外,我们还进行了一项实践上的优化。考虑到计算节点的主要任务是处理计算任务而非后台任务,我们在一台相对空闲的节点上配备了较大的内存,专门用于处理后台任务,如备份元数据。随着文件数量的增加,备份元数据对内存的需求也逐渐增大,因此这种分配方式既确保了计算节点的性能,又满足了后台任务对资源的需求。

元数据引擎选型:Redis vs TiKV

起初,我们使用了两个数据引擎:Redis 和 TiKV。在数据量相对较小,即上千万级别的阶段,我们选择了 Redis。当时,由于我们对这些软件并不十分熟悉,我们参考了相关文档,并考虑到 Redis 的上手难度较低、性能较高,且相关资料丰富,因此决定采用它。然而,随着文件数量的迅速增长,Redis 的性能出现了显著的下降。

具体来说,由于我们为 Redis设 置了 RDB 持久化,当内存占用量增加时,Redis 几乎持续处于 RDB 备份状态,这导致了性能的明显下滑。另外,我们当时采用了哨兵模式,并启用了主从复制以增加可用性,但这也带来了问题。由于是异步复制,主节点宕机后,从节点的数据一致性难以保证。

此外,我们了解到客户端并不会从 Redis 的从节点上读取元数据,而是主要依赖主节点进行读写操作。因此,随着文件数量的增加,Redis 的性能进一步下降。

随后,我们考虑并测试了 TiKV 作为元数据引擎的替代方案。从官方文档来看,TiKV 的性能仅次于 Redis,并且在实际使用中,用户层面的体验与 Redis 相差不大。在数据量达到 5 至 6 亿文件的情况下,TiKV 的表现相当稳定。

TiKV 的另一个优势在于其负载均衡和冗余存储的能力。我们采用了三台节点的配置,每个节点都具备多个副本,确保了数据的安全性和可用性。对于运维团队来说,这些特性极大地减轻了工作负担,提高了系统的稳定性和可靠性。

元数据迁移 :从 Redis 到 TiKV

我们于今年一月份左右进行了系统迁移,并已经稳定使用 TiKV 近半年,期间未出现宕机或任何重大问题。

在迁移初期,由于 Redis 难以支撑高达 5 至 6 亿文件的元数据负载,我们决定采用导出与导入的方法来实现迁移。具体地,我们使用了特定的命令将 Redis 中的元数据导出为统一的 JSON 文件,并计划通过 load 命令将其加载到全新的 TiKV 系统中。

然而,在迁移过程中,我们遇到了一个挑战。我们注意到,某个用户的目录由于文件深度过深或其他原因,在导出时遇到了失败。为了解决这个问题,我们采取了一种创新的方法。我们将除问题目录外的其他所有目录分别导出,并手动打开和拼接这些 JSON 文件,以重新构建完整的元数据结构。

在手动处理这些文件时,我们发现元数据的 JSON 文件结构清晰,拼接操作相对简便。其嵌套结构与目录结构基本一致,这使得我们能够高效地处理元数据。最终,我们成功地将这些文件导入到 TiKV 中,完成了迁移过程。

04 为什么使用对象存储 SeaweedFS?

总体而言,我们遵循了 SeaweedFS 官方文档中推荐的主要组件和基本功能,并未涉及过多新颖或高级特性。在具体部署上,我们采用了 CPU 节点作为核心,并在其上运行了 master 服务器。而数据节点则分布运行在不同的物理节点上,每个节点均运行 volume 服务以处理数据存储。此外,我们在相同的 CPU 节点上运行了 filer 服务器,该服务器为 JuiceFS 提供 S3 服务接口,负责与 JuiceFS 进行对接。从目前的运行情况来看,CPU 节点的负载并不重,主要的数据读写和处理任务均分散在各个 worker 节点上。

在数据冗余和备份方面,我们充分利用了 SeaweedFS 的冗余特性。逻辑上,我们将数据节点划分为两个 Rack。当数据写入时,它会在两个 Rack 中都进行写入,确保在 Rack 0 和 Rack 1 中各有一份备份。只有当两个 Rack 都成功写入数据时,才视为写入成功。虽然这种策略使得我们的硬盘容量在逻辑上几乎减半(因为每份数据都要写两份),但它确保了系统的高可用性和数据安全性。即使其中一个 Rack 中的某个节点出现故障或宕机,也不会影响整体的读写操作和数据安全。

SeaweedFS 的优缺点

首先,从上手难度来看,SeaweedFS 相较于工业界广泛使用的 Ceph,显得更为容易操作。其 master、volume 和 filer 等核心组件均可通过编写脚本来轻松启动。用户只需浏览对应的命令参数,并根据实际需求进行配置,随后通过脚本即可完成启动过程。尽管 SeaweedFS 的文档资料相对较少,但其易用性依然值得肯定。

此外,与另一款常用的对象存储系统 Minio 相比,尽管我们未曾直接使用过 Minio,但根据以往案例和介绍,Minio 在处理大量小文件时可能存在一定的不足。因此,我们在选择时并未考虑 Minio。

SeaweedFS 的另一个显著优点在于其安全性和可用性。通过将数据节点划分为两个 Rack,系统实现了数据的冗余备份,从而提高了数据安全性。同时,其master服务器具备自动调度数据写入的功能,能够自动将数据分配到各个 worker 节点上,实现了负载均衡。此外,SeaweedFS 的扩容过程也相对简单,只需新增机器并连接到 master 节点,系统即可自动进行扩容。

此外,SeaweedFS 官方还推荐了一款 master 管理脚本,该脚本配置简单,仅需编写少量配置即可实现定期自动修复数据冗余和平衡数据分布的功能,极大地提高了系统的维护效率。然而,SeaweedFS 的缺点也不容忽视。其文档资料相对较少且较为陈旧,这可能会给新用户带来一定的学习难度。尽管我们在使用过程中并未遇到其他明显的缺点,但这也是未来需要改进的地方。

05 方案实践中遇到的挑战

使用过程中客户端会异常退出

首先,我们曾遭遇客户端异常退出的情况,经过分析发现这是由于内存溢出(OOM)导致的。随着原数据的不断增长,当计算节点未启用 --no-bgjob 选项时,特定节点因执行高内存消耗任务(主要是自动元数据备份)而导致剩余内存不足,进而无法备份原数据,最终引发 OOM 并导致客户端退出。为了解决这个问题,我们在所有计算节点上添加了--no-bgjob 选项,并利用闲置的数据节点作为专门的后台任务处理节点。

首次大文件的读取较慢

其次,我们在使用初期发现了一个性能问题。特别是在首次读取大文件时,发现读取速度远低于千兆网络带宽的极限。经过深入调查,我们发现这是由于在测试对象存储性能时,未正确配置 JuiceFS 命令的参数。我们没有指定 --storage s3 选项,导致测试默认为本地硬盘性能,而非实际的对象存储性能。这一误解导致了我们对对象存储性能的误判。通过进一步检查,我们发现 SeaweedFS Filer 元数据引擎的性能瓶颈,这主要是因为底层使用的是单个机械硬盘。因此,我们将考虑优化这一环节以提升性能。

解压数据集较慢(大量小文件写入)

最后,我们在日常使用中偶尔需要解压数据集,这涉及到大量小文件的写入操作。我们发现这一过程相较于本地解压明显较慢。在与 JuiceFS 官方沟通后,他们建议我们尝试使用 write-back 加速功能。这一功能允许在文件写入后立即返回,而后台则负责将数据上传到对象存储。我们计划在未来实施这一建议以优化解压性能。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/745237.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

《Three.JS零基础入门教程》第九篇:环境详解

往期回顾: 《Three.JS零基础入门教程》第一篇:搭建开发环境 《Three.JS零基础入门教程》第二篇:起步案例 《Three.JS零基础入门教程》第三篇:开发辅助 《Three.JS零基础入门教程》第四篇:基础变换 《Three.JS零基…

element-ui侧边栏:default-openeds

element-ui侧边栏实现路由跳转后展开对应侧边栏:default-openeds 当菜单是在本地写死时,如果想展开第一块内容、里面就只写1 :default-openeds"[‘1’]" 当菜单是动态获取时,点击跳转之后如何展开对应的菜单,在watch中监…

三元前驱体废水回收镍钴工艺:环保与经济效益的双重胜利

在全球新能源产业迅猛发展的背景下,锂离子电池作为绿色能源的核心组件,其需求量激增,带动了上游材料市场,尤其是三元前驱体材料的蓬勃发展。然而,伴随着行业的快速扩张,三元前驱体生产过程中产生的含镍钴废…

嘉绩咨询低成本连锁品牌招商全案陪跑赋能中小品牌有效招商

以企业战略导航为基石,致力于构建全面招商生态系统的嘉绩咨询,今天宣布推出面向中小品牌的低成本连锁招商全案陪跑服务。这项创新服务是为了帮助具有潜力的中小品牌在市场中迅速构建渠道,通过有效招商策略促进成长。 嘉绩咨询凭借先进的“教育…

PCI认证HSM的特点

PCI认证HSM(硬件安全模块)在支付卡行业中扮演着至关重要的角色,它是确保支付交易数据完整性和机密性的关键组件。以下是关于PCI认证HSM的详细介绍: 一、PCI认证HSM的定义 PCI认证HSM是专门用于支付行业的硬件安全模块,它满足支付卡行业(PCI)的…

【unity实战】Unity中基于瓦片的网格库存系统——类似《逃离塔科夫》的库存系统

最终效果 文章目录 最终效果前言素材下载图片配置获取格子坐标动态控制背包大小添加物品移动物品物品跟随鼠标创建物品的容器,定义不同物品修改物品尺寸修复物品放置位置问题按物品尺寸占用对应大小的格子判断物品是否超出边界范围物品放置重叠,交换物品…

Oracle优化案例-教你在线搞定top cpu的sql(十二)

监控告警阈值load 大于10 SQL如下,太好用了 SELECT A.SQL_ID, A.SESS_COUNT, A.CPU_LOAD, B.SQL_TEXTFROM (SELECT SQL_ID,COUNT(*) SESS_COUNT,ROUND(COUNT(*) / SUM(COUNT(*)) OVER(), 2) CPU_LOADFROM V$ACTIVE_SESSION_HISTORYWHERE SAMPLE_TIME > SYSDATE…

[深度学习] 门控循环单元GRU

门控循环单元(Gated Recurrent Unit, GRU)是一种用于处理序列数据的递归神经网络(Recurrent Neural Network, RNN)变体,它通过引入门控机制来解决传统RNN在处理长序列时的梯度消失问题。GRU与长短期记忆网络&#xff0…

反射及动态代理

反射 定义: 反射允许对封装类的字段,方法和构造 函数的信息进行编程访问 图来自黑马程序员 获取class对象的三种方式: 1)Class.forName("全类名") 2)类名.class 3) 对象.getClass() 图来自黑马程序员 pac…

前端JS必用工具【js-tool-big-box】学习,数值型数组的正向排序和倒向排序

这一小节,我们说一下前端 js-tool-big-box 这个工具库,添加的数值型数组的正向排序和倒向排序。 以前呢,我们的数组需要排序的时候,都是在项目的utils目录里,写一段公共方法,弄个冒泡排序啦,弄…

JNI详解

JNI简介 Java是跨平台的语言,但在有的时候仍需要调用本地代码(这些代码通常由C/C编写的)。 Sun公司提供的JNI是Java平台的一个功能强大的接口,JNI接口提供了Java与操作系统本地代码互相调用的功能。 Java调C 1)使用…

Spring Boot 学习第八天:AOP代理机制对性能的影响

1 概述 在讨论动态代理机制时,一个不可避免的话题是性能。无论采用JDK动态代理还是CGLIB动态代理,本质上都是在原有目标对象上进行了封装和转换,这个过程需要消耗资源和性能。而JDK和CGLIB动态代理的内部实现过程本身也存在很大差异。下面将讨…

VMware vSphere 8.0 Update 3 发布下载 - 企业级工作负载平台

VMware vSphere 8.0 Update 3 发布下载 - 企业级工作负载平台 vSphere 8.0U3 | ESXi 8.0U3 & vCenter Server 8.0U3 请访问原文链接:https://sysin.org/blog/vmware-vsphere-8-u3/,查看最新版。原创作品,转载请保留出处。 作者主页&am…

Java面试八股之JVM内存溢出的原因及解决方案

JVM内存溢出的原因及解决方案 JVM内存溢出(Out Of Memory,OOM)通常是由于程序运行过程中内存使用不当造成的,常见原因及相应的解决方案如下: 原因及解决方案 内存中加载的数据量过大 原因:一次性从数据…

运维入门技术——监控的三个维度(非常详细)零基础收藏这一篇就够了_监控维度怎么区分

一个好的监控系统最后要做到的形态:实现Metrics、Tracing、Logging的融合。监控的三个维度也就是Metrics、Tracing、Logging。 Metrics Metrics也就是我们常说的指标。 首先它的典型特征就是可聚合(aggregatable).什么是可聚合的呢,简单讲可聚合就是一种基本单位可以在一种维…

Verilog刷题笔记48——FSM1型异步复位

题目: 解题: module top_module(input clk,input areset, // Asynchronous reset to state Binput in,output out);// parameter A0, B1; reg state, next_state;always (*) begin // This is a combinational always block// State transition logiccase(…

加拿大魁北克IT人士的就业分析

魁北克省作为加拿大东部的一个重要省份,近年来在IT行业的就业市场上展现出了强劲的增长势头。随着数字化转型的加速,魁北克对IT专业人士的需求日益增加,特别是在软件开发、网络安全、数据分析和人工智能等领域。 热门职位方面,软…

禹晶、肖创柏、廖庆敏《数字图像处理(面向新工科的电工电子信息基础课程系列教材)》Chapter 9插图

禹晶、肖创柏、廖庆敏《数字图像处理(面向新工科的电工电子信息基础课程系列教材)》 Chapter 9插图

201.回溯算法:全排列(力扣)

class Solution { public:vector<int> res; // 用于存储当前排列组合vector<vector<int>> result; // 用于存储所有的排列组合void backtracing(vector<int>& nums, vector<bool>& used) {// 如果当前排列组合的长度等于 nums 的长度&am…

用 Rust 实现一个替代 WebSocket 的协议

很久之前我就对websocket颇有微词&#xff0c;它的确满足了很多情境下的需求&#xff0c;但是仍然有不少问题。对我来说&#xff0c;最大的一个问题是websocket的数据是明文传输的&#xff0c;这使得websocket的数据很容易遭到劫持和攻击。同时&#xff0c;WebSocket继承自HTTP…