近日,AS 全球架构师峰会上海站圆满落地。会上,来自 OPPO 安第斯智能云的唐之享围绕云原生分布式存储 CubeFS 在机器学习和大数据的探索和实践这一主题展开了精彩分享,以下为本次分享的精华内容。
本次分享主要从以下四个方面进行:
CubeFS 的架构设计和关键产品特性;
CubeFS 在机器学习领域的应用和实践,详细说明 OPPO 机器学习存储的演进过程和遇到的问题和挑战,以及如何基于 CubeFS 应对这些问题和挑战;
CubeFS 在大数据的应用和实践;
展望 CubeFS 的未来演进方向。
CubeFS 简介
CubeFS 是云原生计算基金会(CNCF)的新一代云原生开源存储产品,可以提供完整的文件和对象能力,目前处于孵化阶段,技术团队正在积极准备毕业相关事项。
CubeFS 主要分为资源管理模块、元数据子系统、数据子系统以及多协议客户端四个大的模块。其中资源管理模块(Master)负责管理数据节点和元数据节点的存活状态、创建和维护卷 (volume) 信息、元数据分片(metaPartition,简称 mp)和数据分片(dataPartiton,简称 dp)相关的创建和更新。Master 由多个节点构成,通过 Raft 保证服务的高可用。
这里涉及到一个概念——volume,这个是虚拟的逻辑概念,对于文件系统来说,volume 是一个挂载的文件系统;对于对象存储来说,volume 则是对应的一个 bucket。每个 volume 存储用户的数据以及对应数据的元数据,其中数据存储在数据子系统中,可以是多副本引擎的数据分片或者是纠删码引擎的条带中。
元数据保存在元数据节点的 metaPartition 中,元数据的分片是 CubeFS 的一个设计亮点。实际情况中 MetaNode 和 DataNode 可以同机部署,因为一个消耗内存资源,一个消耗是磁盘资源。
除了数据和元数据子系统之外,还有多协议的客户,客户端可以兼容 S3、HDFS 和 POSIX 协议。
CubeFS 的元数据设计是一个亮点,文件系统的元数据管理方式决定了系统的扩展性和稳定性。比较常见的元数据管理方式是静态子树,类似 HDFS 和 CephFS,CephFS 的单机模式元数据节点只能支持 10 亿到 20 亿的元数据,元数据节点会成为瓶颈,而集群模式容易出现热点目录,需要手动运维将热点目录进行拆分。除了静态子树的方式之外,还有 hash 分片的策略,但 hash 分片在扩容新节点时候会面临元数据的迁移,业务对元数据迁移有感知。CephFS 的动态子树是一个比较完善的方案,但由于其实现复杂度较高、稳定性不足,在生产环境很少使用。
元数据系统设计需要解决的关键问题是如何将庞大的元数据进行拆分,并且拆分后的元数据分片尽量均衡,由多个元数据节点共同存储和承担访问负载。唐之享在此详细介绍了 CubeFS 的元数据设计方案。用户数据存在 volume 之中,每个 volume 对应多个 mp,每个 mp 负责一段范围的元数据,比如 mp0 负责[1-10000],mp1 负责[10001-20000],mp2 负责[20001-正无穷],这个正无穷指的最后一个 mp 的最大元数据没有上限,此处之所以这么设计,是因为最后 mp 支持分裂,当最后一个 mp 所在 MetaNode 节点内存使用率达到一个阈值,会把最后一个 mp 分裂成两个 mp,新的 mp 会根据内存权重分配到可用内存更多的 MetaNode 节点上,以此完成元数据的扩展,整个过程无需迁移任务数据,对业务无感。
元数据包含 inode 之外,也会保存 dentry 信息,dentry 记录是(parent_id ,name)到 inode 的索引,需要注意的是 dentry 会和其父目录的 inode 保存在同一个 mp,这样同一个父目录下的所有子文件存在一个分区,遍历该目录只需要访问一个元数据分区就可以获取数据,避免访问整个集群来获取数据。
MetaNode 之间通过 multi-raft 保证数据高可用和数据一致性,每个节点会有多个 mp,不同 MetaNode 上 mp 组成一个 raft-group 组,元数据都是保存的内存中,通过定期快照和 Raft 的 WAL 日志保证高可靠性,具体而言,MetaNode 每五分钟做一次快照,五分钟间隔内有变动的元数据操作会先持久化 WAL 日志,节点故障或者重启后会通过快照+重放 WAL 日志的机制恢复所有的元数据。
CubeFS 的数据子系统分为多副本引擎和纠删码引擎,多副本引擎支持两种协议,顺序写请求采用主从复制协议,这样可以优化 IO 吞吐;随机写采用 multi-raft 协议。大文件会采用分片存储,将大文件按照 128KB 拆分后并发写入到不同 dp 中。dp 由 normal extent 和 tiny extent 组成,大文件分片写入 normal extent 中,小文件采用聚合的方式写入一个 tiny extent 文件中,元数据会记录小文件在聚合文件内的偏移,这样可以有效减少 DataNode 维护的文件数目。
删除数据的空间回收是基于文件系统的 punch hole,可以避免空间回收需要的逻辑到物理映射,有效提升空间回收效率。
纠删码引擎提供低成本、高可靠的在线纠删码存储能力,数据写入直接在客户端编码写入存储节点,无须将数据先聚合到一个临时的多副本系统,然后再异步迁移到纠删码存储,可以避免数据多次迁移导致的流量浪费。元数据为服务基于 Raft 做秒级切换保证一致性和可用性。后台服务定期做数据巡检、坏盘检修、数据均衡等任务来保证数据高可靠。不同模式的编码支持 1、2、3AZ 的部署,多 AZ 部署方式支持 AZ 级别容灾。
客户端支持 S3、POSIX 以及 HDFS 多种协议,通过一套系统做到完美融合,多协议之间共享一套元数据及数据,用户可以直接通过 S3 协议读取通过文件协议写入的数据,反之亦然。数据的统一存储可以提高数据的复用效率,一份数据多处访问,不同业务之间提供租户级别的隔离和租户级别的 QOS,可以最大化提升存储的利用率。
总结一下,CubeFS 是开源的分布式存储产品。
提供多协议兼容 S3/POSIX/HDFS 等多种协议。
支持纠删码和多副本引擎,用户可以根据实际情况选择合适的存储引擎。
其优秀的水平扩展能力,可以帮忙用户快速构建 PB 甚至 EB 级别存储。
元数据全内存缓存和多级缓存技术提供高性能存储。
CubeFS 还支持多租户管理,可以提供细粒度的租户隔离策略,保证不同用户之间的数据安全和隔离。
除此之外,CubeFS 还提供了基于 CSI 插件的快速部署方案,可以方便地在 Kubernetes 上使用 CubeFS。
机器学习的应用
OPPO 的机器学习存储主要分为四个阶段:
第一阶段使用 CephFS 作为存储;
第二阶段使用 CubeFS 和 CephFS 混存;
第三个阶段单独使用 CubeFS 存储;
最后一个阶段使用 CubeFS 存储+多级缓存技术。
接下来具体看看每个阶段遇到的问题和挑战,以及如何应对这些挑战。
第一阶段使用 CephFS 存储集群学习的数据,这个阶段存储节点数目在 150 台,磁盘 1500 块左右。由于 MDS 采用的是主备模式,无法水平扩容,单个 MDS 承受 10 亿级别的元数据访问,节点负载过高导致 MDS 时延上升,训练的 IO 吞吐下降,大量 GPU 训练的利用率低。MDS 在稳定性方面也存在问题,用户频繁的超大目录遍历导致 oom,服务的恢复周期较长。
最直接的解决方案是分而治之,将大的 CephFS 集群拆分成 6 个小集群,保证每个集群规模控制 500 块盘以内,小集群模式在稳定性确实有提升,但是小集群模式并不是真的小而美。首先小集群模式的存储资源利用率不高,通常需要将存储水位控制在 70%左右来应对突发的业务增长,其次面对百亿参数的大规模机器学习训练,小集群无法满足高 IO 的吞吐要求。这个阶段 CubeFS 技术团队也开始了灰度和验证 CubeFS。
总的来看,这一阶段机器学习存储的主要特点是海量小文件、超大目录热点目录以及访问时延敏感。在经过一段时间验证了 CubeFS 的稳定性、扩展性以及性能方面都能满足机器学习的存储需求之后,最终使用 CubeFS 作为统一存储。依靠 CubeFS 可扩展的元数据服务,元数据节点不会成为单点瓶颈,用户的元数据会均匀分配到不同 MetaNode 节点,由所有 MetaNode 节点共同承担,有效地解决热点目录的问题。最终将机器学习超过 70 亿的文件数量,总存储量超过 30PB 的数据全量存储在 CubeFS 中,SLA 也从 3 个 9 提升到 4 个 9,元数据的访问时延从 10ms 降低到 1ms,全年稳定运营无故障,为后续机器学习的高性能存储打下基础。
第四阶段,进入混合云计算阶段,这个阶段对混合云弹性计算的需求主要是为了合理利用资源,降本增效。这一阶段会在 OPPO 私有云维护常态化的 GPU 算力水位,而应对突发的算力需求,采用公有云的 GPU 算力,通过这种混合云的弹性计算来节约计算成本。但是这也带来了一个挑战,由于公有云机房到私有云机房的专线时延是 2ms,导致公有云训练的时延比私有云的效果差两到三倍。
为了满足弹性计算的需求,CubeFS 技术团队提出了几种不同的解决方案:
方案一:将数据存储在公有云的文件系统中,公有云的训练访问公有云的文件系统,以此来减少机房之间的时延。这种方案抛开昂贵的数据迁移代价不谈,还存在以下问题,数据是全量迁移还是部分迁移,如果全量迁移数据,公有云已经有全量的数据,无法做到弹性计算;如果是部分迁移,私有云的 CubeFS 和公有云的文件系统存在数据一致性需要解决;另外考虑终端用户的数据隐私安全问题,将数据保存公有云可能会产生数据安全合格风险。
方案二:在公有云部署一套 CubeFS 文件系统,该方案除了存在方案一的相关问题之外,由于 GPU 的云盘空间有限,还需要额外购买裸金属服务器来部署 CubeFS,增加存储成本。
通过深入了解集群学习的训练过程的特点,发现大规模 AI 训练的 IO 有以下特点,每一轮迭代 epoch 会反复读取同一批数据,通常单次训练会跑上万轮。总的来说,AI 训练的 IO 特征就是在某个训练集的反复并且多次读取的一个过程。基于这个特征,利用 CubeFS 作为统一存储结合多级缓存的方案非常适合。
第一轮训练将数据从私有云 CubeFS 加载到公有云的缓存节点,客户端会缓存元数据 inode 和 dentry 信息,可以大量减少训练过程使用 fuse 客户端的 loopup 和 open 操作的元数据查询延时开销,并且元数据缓存可以指定缓存文件数量,最大可以支持千万级别的文件。GPU 的云盘(通常是 1TB)可以作为数据缓存盘,通过指定缓存目录和配置 LRU 策略,无须申请额外资源就可以缓存数据。通过缓存加速策略,RESNET18 模型下 dataload worker 分别是 1 和 16 的时候,整体性能提升了 360%和 114%,即使相比私有云的训练也有 12-17 的性能提升。
大数据的应用
大数据的存储过程也可以分为四个阶段:
第一阶段是 HDFS 存储,这一阶段主要面临的是存储成本和运维复杂高等问题;
第二阶段是使用对象存储做降冷,来解决 HDFS 集群高成本的问题,但是由于对象存储不支持文件语义,在 list 等操作时候代价较高;
第三阶段使用 CubeFS 来承接冷数据;
第四阶段阶段是使用 CubeFS 作为统一存储。
大数据最开始使用 HDFS 存储也面临了一些挑战。
首先是 HDFS 集群数目多,如下图所示,只是大数据业务的一部分 HDFS 集群,除了集群数量多之外,多个集群的存储空间资源紧张,需要集群间不断腾挪机器来满足日益增长的存储需求。并且 HDFS 集群采用的是存算混合机型,这种机型单位存储成本高、能耗大,所以这一阶段面临的主要是存储成本过高、集群管理复杂的问题。
第二阶段主要采用对象储保存大数据的冷数据,这个阶段会将大数据的冷数据迁移到对象存储中,依靠对象存储的低成本优势来解决大数据业务面临的成本问题。但是对象存储承担大数据的冷数据有个天然的问题,就是不支持文件语义,业务的 list 和 rename 操作时候代价非常高昂,rename 操作需要先对数据做 copy 然后再删除旧的数据,整个过程代价极高。
第三阶段是基于 CubeFS 的来存储大数据冷数据,CubeFS 不仅能够提供低成本的存储,本身也支持文件语义。目前已经使用 CubeFS 存储超过 100PB 的大数据冷数据,整体存储成本比使用 HDFS 节约 40%以上,即使比使用对象存储的成本也有所下降,并且整个降冷过程更快、更节约资源。
最后一个阶段是使用 CubeFS 作为统一存储,冷数据采用 CubeFS 低成本、高可靠的纠删码引擎,热数据采用 CubeFS 三副本引擎。CubeFS 统一存储可以支持更大 IO 并发需求,例如 Flink 的 check point 集群,需要定期将任务持久化到存储,会产生很多频繁大 IO 请求,小规模的 HDFS 集群需要靠扩容解决,导致集群整体存储利用率不高,存储成本增加,而使用 CubeFS 统一存储,可以提升整体存储利用率并且能够满足大 IO 的要求。
大数据业务经历了这个四个阶段的存储演进,简单来说,大数据存储目前的需求就是以下几点。最核心的需求就是降本增效,这个也是目前很多公司的关键目标,在降本增效的同时需要保证系统的可用性、数据的可靠性以及运维的便捷性。
关于 CubeFS 如何助力大数据降本,第一个策略是从数据冗余度出发, CubeFS 本身提供了弹性可变的副本机制,用户可以根据业务特性选择特定数量的副本数目。举个例子,大数据的 Shuffle 业务产生的是临时数据,这个业务场景很适合采用单副本存储来节约存储成本。
除了弹性副本之外还可以采用低成本的纠删码,不同冗余度的编码支持可配,用户可以根据对数据耐久度的需求来选择合适的编码,例如可以选择支持 AZ 级别容灾的编码,在降低数据冗余度的同时兼顾数据可靠性。
除了软件层面的降本之外,CubeFS 技术团队还在硬件层面做了降本优化,这里主要是选择一些高密的存储服务器,高密存储服务器单位存储量的成本和功耗都更低,整体的存储成本也更低。
除了节约存储成本之外,CubeFS 技术团队也特别关注大数据存储的性能,通过多级缓存技术可以在 Client 节点上同机部署 BlockCache 组件,在内存缓存元数据,利用本地磁盘来缓存数据,元数据和数据就近访问可以提升数据的读性能,当然由于本地磁盘容量有限,需要配置一定的缓存淘汰策略。
本地缓存之外还有全局缓存,如果业务对缓存容量需求更大,可以使用多副本 DataNode 作为缓存,例如利用 DataNode 作为全局缓存,相比本地缓存,全局缓存容量很大,并且副本数目可以调整。
除了利用多级缓存做优化之外,CubeFS 对小文件也有特定的优化,在前面机器学习的场景有提到过,机器学习主要通过缓存元数据的 inode 和 dentry 来优化读性能。其实多副本引擎的小文件会聚合到一个大文件中,小文件聚合会减少 DataNode 管理的文件数量。纠删码引擎写入小文件会采用填充的方式,这样小文件读取时候只访问第一块数据,可以避免跨 AZ 的读流量。顺便提一点,纠删码的读写采用 quorum 机制,RS(n,m) 的编码任意写 n+1 份(这里+1 还是加几可以配置)就成功,读任意 n 份就返回成功,这样可以有效避免长尾的时延问题。
下面是一个大数据热数据在 CubeFS 的应用实例分享,传统大数据的 shuffle 任务中 map 和 shuffle-work 是同机部署,这样 shuffle-work 读写数据会抢占 CPU 资源,另外由于单机存储的空间有限,可能因为任务分配资源不均衡等问题导致任务失败。remote shuffle 是 OPPO 大数据团队开源的一个项目,将 shuffle-worker 与 map 解绑,在云上部署 shuffle-worker,使用分布式存储 CubeFS 存储 shuffle 过程中产生的临时文件。Shuffle 过程产生的是临时数据,即使数据丢失可以重新生成任务,对数据可靠性要求不高,更加关注成本;临时数据需要快速清理;另外 shuffle 对数据读写的吞吐量和性能要求较高,在多任务并行场景对读写带宽需求较大,测试过程中会发现经常能把网卡、磁盘打满导致机器负载整体能够达到 80%以上。
针对这些存储特点,CubeFS 提供以下的解决方案:
提供单副本存储,虽然会存在坏盘会导致数据丢失,但是就像上面所说, Shuffle 场景下产生的是临时数据,数据丢失后任务可以重做,代价就是任务时延增加,相比于正常情况下性能提升和成本降低,这是一个合理的权衡。
利用 CubeFS 的就近读写的能力,可以将 Shuffle-worker 与 CubeFS 的数据节点同机部署,这样 Shuffle-worker 在读写数据的时候,就不需要经过网络,也不受网卡带宽的限制,直接从本机的 DataNode 上读取数据,从而提高 Shuffle-worker 的数据读写性能。
提供异步删除的功能,将待清理的目录先 rename 到一个临时待删除的目录下,然后 CubeFS 后台定时扫描,异常清理待删除目录。一次 rename 操作在 CubeFS 只需要跟后端交互两次,相比于之前串行的删除目录下所有文件,延时由 N 个 ms 降低到了稳定的 2ms 左右。使用 CubeFS 存储将 Shuffle 的时延减低 20%,成本降低 20%。
总结来说,CubeFS 帮助大数据服务实现了快、稳、省的目标。有效提升数据的访问性能、提高存储服务的稳定性并大量地节约存储成本,降低总 TCO。
未来演进
未来,CubeFS 将会在下面几个方面提供新的特性:
智能分层,未来会根据数据的特性和访问频度将数据分层存储,例如将热数据保存三副本的 SSD 中,而将不常用的冷数据存储在 HDD 或者直接存储到纠删码引擎,以实现更好的性能和资源利用率的提升。
多版本快照能力,机器学习存储过程可能存在多人同时修改文件的需求,对文件安全要求性很高,通过多版本快照能力记录文件变化的过程,可以帮忙用户快速恢复到特定版本混合云多云的支持,帮助用户充分利用不同云服务的优势和特性,实现多云的管理。除此之外还会在 GDS、数据加解密以及数据回收站等方面持续演进。
唐之享总结道,CubeFS 是开源的云原生分布式存储产品,高效、稳定、弹性;助力大数据与 AI 无限潜能,让大家存得放心、用得省心!同时呼吁大家参与到社区共建中,一起推动 CubeFS 的发展,为更多企业提供高性能、高可靠的分布式存储解决方案。
评论