随着BIGO机器学习平台模型和数据量的增长,对底层依赖的文件系统提出了更多的需求,如多租户、高并发、多机房高可用、高性能、云原生等特性。BIGO大数据平台存储团队在经过多方技术选型,多角度对比之后发现CubeFS有很多特性适合机器学习平台的应用场景。
本文主要介绍BIGO大数据平台存储团队将CubeFS上线到生产环境的主要实践经验与开发工作。大部分的功能开发及问题修复也贡献到开源社区,经过半年多的努力,团队中三位同学获得CubeFS开源社区的Collaborator,提升了BIGO在CubeFS开源社区的影响力。
|CubeFS简介
CubeFS是一个专为大规模容器平台设计的分布式文件系统,是国内首个云原生开源分布式存储系统,2022年7月成功晋级为CNCF孵化项目。它为运行在Kubernetes容器平台之上的云原生应用提供了多租户隔离、POSIX兼容、支持Fuse挂载、高并发高吞吐的文件系统,同时也提供对象存储功能,支持S3/HDFS协议访问。CubeFS基于volume管理实现租户隔离,内部实现了高效的数据与元数据弹性扩展、随机小写顺序化、强一致复制算法等核心特性,数据默认是以三副本的方式存储,也支持多种纠删码模式来降低存储成本。
目前CubeFS的主要应用在大规模机器学习、大数据存储、云存储(如K8S的后端存储)和其他传统的IT应用方面,比如海量数据的备份存储,包括数据库备份、MySQL底层存储(历史表)、人工智能平台模型训练的后端存储、点击流业务Nginx日志存储成本结算、Elasticsearch底层存储、Hbase后端存储等。CubeFS 基于 Container Storage Interface (CSI)接口规范开发了 CSI 插件,以支持在 Kubernetes集群中使用CubeFS。
BIGO为什么选择CubeFS
1、机器学习平台的业务场景有上万个客户端同时读写,对并发读写要求较高;
2、小文件较多,需要做数据聚合,规避磁盘的IO瓶颈问题;
3、小文件较多的场景对元数据开销较大,需要有弹性元数据扩展特性;
4、需要支持多机房高可用;
5、业界已有不少公司将CubeFS在机器学习平台和容器平台落地。
|CubeFS架构
图1 CubeFS整体架构
CubeFS主要由资源管理节点、元数据子系统和数据子系统组成,提供兼容POSIX/Hadoop接口,简化了上层应用开发,降低新用户学习难度。如果要使用对象存储功能,也可以启动对象存储节点,CubeFS提供了兼容S3语义的访问协议,可以通过Amazon S3 SDK或者是s3cmd等工具访问。用户使用CubeFS,只需先创建对应的卷(每一个卷代表一个文件系统实例),通过挂载或者SDK的方式进行访问。一个卷可以被多个容器或者宿主机挂载,多个客户端可以同时访问同一个卷,每个卷之间相互隔离。
元数据子系统
CubeFS实现了分布式元数据子系统,由多个元数据节点组成,提供高效的元数据索引和可扩展元数据管理。在CubeFS中,每个Inode代表文件系统中的一个文件或目录,每个Dentry代表一个目录项,由ParentID和Name组成。通过两个索引规则,ParentID+Name -> InodeID和InodeID -> Inode,进行查找。每个元数据分片通过两个B-Tree,InodeTree和DentryTree,来加快元数据索引速度。
每个元数据节点有一个或多个元数据分片(Meta Partition),一个卷的元数据通常由多个元数据分片组成,分布在不同的元数据节点上;不同卷的元数据分布在不同的元数据分片上,每个元数据分片只归属于某一个卷。每个元数据分片会有多个副本分布在不同元数据节点上,副本之间通过multiRaft协议来复制数据,保障数据一致性和高可用性。每个卷可以通过增加元数据分片来提升并发处理的能力。
如下图展示了两个卷各自包含的元数据分片,以及元数据分片在元数据节点上的分布情况。
图2 元数据分片
对于同一个卷下面的多个元数据分片,是如何组织起来构建一个文件系统的目录树。在CubeFS中规定每个文件/目录的Dentry与父目录的Inode在同一个元数据分片上,而该文件/目录的Inode则是在这个卷的元数据分片中轮询或者随机选择一个写入。这种设计方式,能够较好的将元数据分散到各个元数据分片,避免大量请求落在某个节点上成为热点。
当集群的元数据子系统容量使用到达一定阈值,可以通过新增元数据节点进行扩容。同时,CubeFS提供迁移功能,当某个元数据节点成为热点瓶颈,可以将该节点的元数据分片迁移到其他节点来均衡负载。
数据子系统
图3 数据子系统
数据子系统主要分为副本子系统和纠删码子系统,两种子系统可单独部署,也可以同时部署,我们这里主要介绍副本子系统。副本子系统由多个数据节点组成,每个数据节点管理多个数据分片,每个数据分片通过multiRaft协议复制多个副本分布在不同数据节点上。数据分片由多个extent组成,每个extent就是本地文件系统上的一个文件,用于写入数据。
当数据子系统使用容量达到一定阈值,可以通过增加数据节点对数据子系统进行扩容。为了能满足大文件和小文件支持顺序随机访问的多租户需求,副本子系统采用两种不同的复制协议,以确保较高IO性能和数据强一致性。
存储大文件时,会将数据写入到一个或者多个extent,不同的文件存储在不同的extent中。存储小文件时,会将多个小文件聚合在一个extent中,并将每个文件内容的物理偏移量记录在相应的元数据中,这样的好处是可以减少本地文件系统的元数据开销和提高磁盘写入效率。小文件聚合机制的实现有一个难点是需要设计垃圾回收机制,管理删除数据导致的文件空洞。CubeFS通过巧妙使用底层文件系统提供的穿洞接口(fallocate()),可以直接释放磁盘空间,不需要实现垃圾回收机制,简化了小文件聚合机制的实现。
副本子系统采用两种不同的复制协议来处理不同的文件写入操作。当数据顺序写入时,采用主备复制协议来保证副本的个数和较高的IO吞吐;当数据是随机写时,会覆盖现有的文件内存,则采用MultiRaft协议来复制数据。MultiRaft协议复制数据会牺牲部分IO性能,但是会大大提高数据一致性,考虑到覆盖写的场景相对较少,这种处理方式也是可以接受的。
资源管理节点
资源管理子系统由多个资源管理节点组成,负责管理整个集群的状态,包括元数据节点、数据节点、卷、元数据分片、数据分片的状态,节点之间通过raft协议将元数据持久化到Rocksdb中保证集群元数据一致。
资源管理节点基于利用率的分布策略来分配资源,比如创建卷时,根据集群中的磁盘和内存空间使用情况,选择可使用资源较多的节点创建数据/元数据分片。当某个卷的数据/元数据分片可使用资源较少时,会自动在集群中选择适合节点创建新的分片,并保证每个分片的不同副本分布在不同的机器上。
资源管理节点定期获取元数据和数据子系统状态信息,客户端则定期从资源管理器拉取元数据和数据分片信息,文件操作由客户端发起,直接与数据和元数据节点通信,无需资源管理节点介入。
|BIGO的实践和优化
针对机器学习平台提出的需求,我们于2022年11月份开始做分布式系统选型,最终选定CubeFS,目前机器学习平台的日志数据迁移已完成,系统稳定运行。在测试验证过程修复了一些问题,并针对系统稳定性和运维便捷性进行了一些开发。我们将大部分代码贡献到CubeFS社区,合入CubeFS主干分支代码,并应用到最新发布的CubeFS-release-3.2.1版本中。
多机房高可用部署:
我们选择将数据分布到多个机房进行部署,避免单机房故障导致业务不可用。在CubeFS中,默认是用3副本来存储数据,并以数据分片为粒度做数据冗余,通过raft协议保证数据一致,相同数据分布的多个副本不会写入到相同机房。当数据分片一个副本不可用时,数据分片状态变为可读,数据需要选择其他数据分片继续写入。所以我们选择4个机房进行高可用部署,将MetaNode节点和DataNode节点均匀分布到4个机房,当有一个机房故障时,仍然能保证数据写入到其他3个机房,拥有3副本。
系统稳定性方面:
1、修复多个影响系统稳定性的bug,包括1个元数据不一致的bug和2个导致客户端报错的bug,提高了系统稳定性。
图4 修复的问题
2、开发审计日志功能,社区版本是在客户端收集审计日志,不适合BIGO的应用场景。我们重新开发了这个功能,将审计日志放到服务端收集,metanode写完查看审计日志后可以被Filebeat收集并写入Pulsar集群,最终写入到ClickHouse保存,这样可以通过SQL语句进行多维度查询。
图5 CubeFS审计日志框架
3、由于之前使用其他文件服务的经验,用户希望能尽快发现服务端异常卡死的情况,并在服务端卡死的场景下有超时退出功能。我们基于客户的需求,开发了在客户端检测超时请求和超时报错功能,可以知道哪个进程哪个操作出现超时,方便快速排查超时原因,并将检测数据上报到监控系统,帮助客户快速发现问题。并且在服务端异常卡死的情况下应用程序可以超时退出并返回特定的错误,避免重新挂载客户端。
图6 client超时检测与告警机制
4、集群识别功能,CubeFS中没有集群唯一ID进行识别,使用错误的配置会将节点加入到其他集群,导致原有集群节点丢失。我们开发了集群识别功能,通过命令生成集群唯一ID,在metanode和datanode启动时会从master获取该ID行检查,确保不会加入到其他集群。并且能够兼容新集群和旧集群,减少运维过程中的风险。
运维便捷性方面:
1、多方位增加监控,更方便查看系统状态,辅助定位系统问题,开发运维工具,提供高效的运维命令。
2、开发自动补充数据副本功能,在CubeFS中,数据以三副本方式保存在不同datanode的磁盘上。但由于磁盘可能损坏,造成副本减少,当三个副本都损坏后,就会造成数据丢失。因此我们开发了自动补充数据副本功能,当检测到数据副本丢失,会自动调度到适合的节点上补充数据副本,通过自动化修复的方式减少人工运维成本。
3、数据节点自动下线和磁盘自动下线功能,当数据节点进程由于某种原因退出时,会导致多个datapartition缺失一个副本,需要尽快将该节点下线,减少数据丢失风险。我们开发了数据节点自动下线功能,当datanode进程退出后,master通过心跳检测发现该节点异常,会自动调度下线该节点的datapartition至其他节点上,并控制下线速度保证不对集群性能造成太大影响。同时,也开发了磁盘自动下线功能,当有磁盘损坏时,由master自动调度将该磁盘上面的datapartition迁移到其他节点上。
图7 自动下线功能
4、元数据节点启动加速,元数据节点是将元数据都加载到内存中,当集群中文件数较多时,重启元数据节点需要较长时间,特别是升级版本时,需要重启整个集群中所有的元数据节点,时间会很长。我们开发了并发加载元数据功能,将元数据节点启动时间缩短至原来的50%左右。
5、文件统计功能,为了方便分析不同volume的业务特性和负载情况,我们需要统计出每个volume的文件大小分布情况,比如该volume是使用大文件比较多还是小文件比较多,文件大小的占比情况,并且该功能不能对整个集群的性能有太大影响。我们通过后台任务解析元数据的快照文件,进行volume分类,将数据上报到监控系统,这样就可以在监控页面查看每个volume的文件分布情况。下图显示某个volume的文件分布情况。
图8 文件大小分布统计
6、客户端热升级功能,用户使用cubefs时,通过cfs-client挂载fuse访问,当cfs-client升级时,用户需要先暂停业务,再重新挂载目录,这种使用方式非常不友好。当前cubefs已经提供了cfs-client热升级功能,原理如下图:
图9 client热升级原理
升级过程主要包含如下步骤:
我们测试过程中修复了新客户端的缓存信息恢复不全的问题。同时也发现另一问题,旧客户端退出时间点太早,容易出现旧客户端已经退出,新客户端启动失败,影响业务。为了减少这种情况发生,我们对现有的实现机制进行改进,当旧客户端将相关信息保存之后,旧客户端不退出,继续挂起,等新客户端恢复数据完成之后再将旧客户端退出。
图10 改进后的client热升级原理
主要的改动点如下:
▼版权声明