本期内容咱们邀请到了来自蚂蚁团体的开发工程师陈传迎老师,给大家分享Alluxio在蚂蚁团体是如何反对大规模模型训练的。

首先是对于引入Alluxio的背景:
为什么要引入Alluxio?
Alluxio到底解决了什么问题?

带着这些问题,咱们疾速get陈老师分享的核心内容:
第一局部:稳定性建设

稳定性建设次要从两块进行:worker register follower和master迁徙。

【价值】能够把整个集群做FO的工夫管制在30秒以内,如果再配合一些其余机制,比方client端有一些元数据缓存机制,就能够达到一种用户无感知的条件下进行FO。

第二部份:性能优化

性能优化次要进行了follower read only的过程。

【价值】单个集群的吞吐曾经造成了三倍以上晋升,整个性能也会晋升上来,能够反对更大并发的模型训练任务。

第三局部:规模晋升

规模晋升次要是横向扩大。

【价值】模型训练汇合越来越大,能够把这种模型训练引入进来,对外提供反对。

以上仅为大咖演讲概览,残缺内容点击视频观看:

附件:大咖分享文字版残缺内容可见下文

背景介绍

首先是咱们为什么要引入Alluxio,其实咱们面临的问题和业界基本上是雷同的:
√ 第一个是存储IO的性能问题,目前gpu的模型训练速度越来越快,势必会对底层存储造成肯定的压力,如果底层存储难以反对目前gpu的训练速度,就会重大制约模型训练的效率。
√ 第二个是单机存储容量问题,目前咱们的模型汇合越来越大,那么势必会造成单机无奈寄存的问题。那么对于这种大模型训练,咱们是如何反对的?
√ 第三个是网络提早问题,目前咱们有很多存储解决方案,但都没方法把一个高吞吐、高并发以及低延时的性能交融到一起,而Alluxio为咱们提供了一套解决方案,Alluxio比拟小型化,随搭随用,能够和计算机型部署在同一个机房,这样能够把网络延时、性能损耗降到最低,次要出于这个起因咱们决定把Alluxio引入蚂蚁团体。

以下是分享的核心内容:总共分为3个局部,也就是Alluxio引入蚂蚁团体之后,咱们次要从以下三个方面进行了性能优化:第一局部是稳定性建设、 第二局部是性能优化、第三局部是规模晋升。

稳定性建设

首先介绍为什么要做稳定性的建设,如果咱们的资源是受k8s调度的,而后咱们频繁的做资源重启或者迁徙,那么咱们就须要面临集群频繁的做FO,FO的性能会间接反映到用户的体验上,如果咱们的FO工夫两分钟不可用,那么用户可能就会看到有大量的报错,如果几个小时不可用,那用户的模型训练可能就会间接kill掉,所以稳定性建设是至关重要的,咱们做的优化次要是从两块进行:一个是worker register follower,另外一个是master迁徙。

Worker Register Follower

先介绍下这个问题的背景:上图是咱们Alluxio运行的稳固状态,由master进行元数据服务,而后外部通过raft的进行元数据一致性的同步,通过primary对外提供元数据的服务,而后通过worker节点对外提供data数据的服务,这两者之间是通过worker注册primary进行一个发现,也就是worker节点的发现,这样就能够保障在稳固状态下运行。那如果这时候对primary进行了重启,就须要做一次FO的迁徙,也就是接下来这个过程,比方这时候对primary进行了重启,那么外部的standby就须要通过raft进行从新选举,选举进去之前,其实primary的元数据和worker是断联的,断连的状态下就须要进行raft的一致性选举,进行一次故障的转移,接下来如果这台机器选举进去一个新的primary,这个时候work就须要从新进行一次发现,发现之后注册到primary外面,这时新的primary就对外提供元数据的服务,而worker对外提供data数据的服务,这样就实现了一次故障的转移,那么问题点就产生在故障产生在做FO的时候,worker发现新的primary后须要从新进行一次注册,这个局部次要面临三个问题:

第一个就是首个worker注册前集群是不可用的,因为刚开始首个worker复原了新的primary领导能力,如果这个时候没有worker,其实整个primary是没有data节点的,也就是只能拜访元数据而不能拜访data数据。

第二个是所有worker注册过程中,冷数据对性能的影响。如果首个worker注册进来了,这时就能够对外提供服务,因为有data节点了,而在陆续的注册的过程当中如果首个节点注册进来了,而后后续的节点在注册的过程当中,用户拜访worker2的缓存block 的时候,worker2处于一种miss的状态,这时候data数据是失落的,会从现存的worker中选举进去到底层去读文件,把文件读进来后从新对外提供服务,然而读的过程当中,比如说worker1去ufs外面读的时候,这就牵扯了一个预热的过程,会把性能拖慢,这就是注册当中的问题。

第三个是worker注册实现之后的数据冗余清理问题。注册实现之后,其实还有一个问题就是在注册的过程当中一直有大量数据进行了从新预热,worker全副注册之后,注册过程中从新缓存的这部分数据就会造成冗余, 那就须要进行预先清理,依照这个重大等级其实就是第一个worker注册前,这个集群不可用,如果worker规格比拟小,可能注册的工夫2-5分钟,这2-5分钟这个集群可能就不可用,那用户看到的就是大量报错,如果worker规格比拟大,例如一个磁盘有几tb的体量,齐全注册上来须要几个小时。那这几个小时整个集群就不可对外提供服务,这样在用户看来这个集群是不稳固的,所以这个局部是必须要进行优化的。

咱们目前的优化计划是:把所有的worker向所有的master进行注册,提前进行注册,只有worker起来了 那就向所有的master从新注册一遍,而后两头通过这种实时的心跳放弃worker状态的更新。那么这个优化到底产生了怎么成果?能够看下图:

这个时候如果primary被重启了,外部通过raft进行选举,选举进去的这个新的primary对外提供服务,primary的选举须要经验几局部:第一局部就是primary被重启之后,raft进行自发现,自发现之后两者之间进行从新选举,选举进去之后这个新的primary通过catch up后就能够对外提供服务了,就不须要从新去获取worker进行一个register,所以这就能够把工夫齐全节省下来,只须要三步:自发现、选举、catch up。

这个计划的效率十分高,只须要30秒以内就能够实现,这就大大缩短了FO的工夫。另一个层面来说,这里也有一些负面的影响,次要是其中一个master如果进行了重启,那么对外来说这个primary是能够提供失常服务的,而后这个standby重启的话,在对外提供服务的同时,worker又须要从新注册这个block的元数据信息,这个block元数据信息其实流量是十分大的,这时会对以后的worker有肯定影响,而且对局部注册上来的master性能也有影响,如果这个时候集群的负载不是很重的话,是齐全能够疏忽的,所以做了这样的优化。

Master的迁徙问题

如图所示,其实刚开始是由这三者master对外提供服务, 这三者达到一个稳固的状态,而后worker注册到primary对外提供服务,这个时候如果对机器做了一些腾挪,比方standby3把standby1替换掉,而后standby4把standby2替换掉,而后新的primary把老的primary替换掉,这个时候新的这个master的集群节点就是由这三者组成:standby3、standby4、新的primary,依照失常的流程来说,这个worker是须要跟以后这个新的集群进行建联的,维持一个失常的心跳,而后对外提供服务,然而这时候并没有,次要起因就是worker辨认的master信息其实是一开始由configer进行动态注入的,在初始化的时候就曾经写进去了,而且后盾是动态治理的,没有动静的更新,所以永远都不能辨认这三个节点, 辨认的永远是三个老节点,相当于是说这种场景间接把整个集群搞挂了,对外没有data节点就不可提供服务了,复原伎俩次要是须要手动把这三个新节点注册到configer当中,从新把这个worker重启一遍,而后进行辨认,如果这个时候集群规模比拟大,worker节点数量比拟多,那这时的运维老本就会十分大,这是咱们面临的master迁徙问题,接下来看一下怎么应答这种稳定性:

咱们的解决方案是在primary和worker之间维持了一个主心跳,如果master节点变更了就会通过主心跳同步以后的worker,实现实时更新master节点,比方standby3把standby1替换掉了,这个时候primary会把以后的这三个节点:primary、standby2、standby3通过主心跳同步过去给以后的worker,这个时候worker就是最新的,如果再把standby4、standby2替换,这时候又会把这三者之间的状态同步过去,让他放弃是最新的,如果接下来把新的primary加进来,就把这四者之间同步过去,重启之后进行选举,选举进去之后 这就是新的primary,因为worker节点最初的一步是存着这四个节点,在这四个节点当中便当寻找以后的leader,而后就能够辨认新的primary,再把这三个新的master同步过去 这样就达到一个平安的迭代过程,这样的状况下再受资源调度腾挪的时候,就能够稳固的腾挪上来。

以上两局部就是稳定性建设的内容。

性能优化

性能优化咱们次要进行了follower read only的过程,首先给大家介绍一下背景,如图所示:

这个是以后Alluxio的整体框架,首先client端从leader拿取到元数据,依据元数据去拜访失常的worker,leader和standby之间通过raft进行与元数据一致性的同步,leader进行元数据的同步只能通过leader发动而后同步到standby,所以说他是有先后顺序的。而standby不能通过发动新的信息同步到leader,这是一个违反数据一致性准则的问题。

另一部分就是以后的这个standby通过后面的worker register follower的优化之后,其实standby和worker之间也是有肯定分割的,而且数据都会收集上来,这样就是standby在数据的完整性上曾经具备了leader的属性,也就是数据基本上和leader是保持一致的。

而这一部分如果再把它作为backup,即作为一种稳定性备份的话,其实就是一种资源的节约,想利用起来但又不能突破raft数据一致性的规定,这种状况下咱们就尝试是不是能够提供只读服务, 因为只读服务不须要更新raft的journal entry,对一致性没有任何的影响,这样standby的性能就能够充分利用起来,所以说这里想了一些优化的计划,而且还牵扯了一个业务场景,就是如果咱们的场景实用于模型训练或者文件的cache减速的,那只有第一次预热的时候数据才会有写入,前面是只读的,针对大量只读场景利用standby对整个集群的性能取胜是十分可观的。

上面是具体的优化计划,如图所示:

次要是针对后面进行的总结,所有的worker向所有的standby进行注册,这时候standby的数据和primary的数据基本上是统一的,另一部分还是primary和worker之间保护的主心跳,这个时候如果client端再发动只读申请的时候,就会随机散列到以后所有的master上由他们进行解决,解决实现之后返回client端,对于写的申请还是会发放到primary下来。而后在不突破raft一致性的前提下,又能够把只读的性能晋升,这个机器扩大进去,依照失常推理来说,只读性能可能达到三倍以上的扩大,通过follower read理论测验下来成果也是比拟显著的。这是咱们引入Alluxio之后对性能的优化。

规模晋升

规模晋升次要是横向扩大,首先看一下这个问题的背景:如图所示:

还是Alluxio的框架,master外面次要蕴含了很多构件元素,第一个就是block master,第二个是file master,另外还有raft和snapshot,这个局部的次要影响因素就是在这四个方面:
√ Bblock master,如果咱们是大规模集群创立下,block master面临的瓶颈就是内存,它会强占掉大量master的内存,次要是保留的worker的block信息;
√ File master,次要是保留了inode信息,如果是大规模场景下,对本地存储的压力是十分大的;
√ Raft面临的同步效率问题;
√ snapshot的效率,如果snapshot的效率跟不上,能够发现后盾会积压十分多journal entry,这对性能晋升也有肯定影响;

做了一些测试之后,在大规模场景下,其实机器规格不是很大的话,也就反对3-6个亿这样的规模,如果想反对10亿甚至上百亿这样的规模,全副靠扩充存储机器的规格是不事实的,因为模型训练的规模能够有限增长,然而机器的规格不能够有限裁减,那么针对这个问题咱们是如何优化的呢?

这个优化咱们次要借鉴了Redis的实现计划,就是能够在底层对元数据进行分片,而后由多个cluster集群对外提供服务,这样做的一个益处就是对外能够提供一个整体,当然也能够采取不同的优化策略,比方多个集群齐全由用户本人去掌控, 把不同的数据调配到每一个集群上,但这样对用户的应用压力就会比拟大。先来介绍一下这个框架,首先咱们把这个元数据进行一个分片,比方用户拿到的整体数据规模汇合比拟大,单集群放不下了,这时候会把大规模的数据汇合进行一个分片,把元数据进行一些哈希(Hash)映射,把肯定hash的值映射到其中某一个shard上,这样cluster这个小集群就只须要去缓存对应局部key对应的文件,这样就能够在集群下面有目标性的进行抉择。

那么接下来其余的数据就会留给其余cluster,把全量的hash调配到一个设定的集群规模上,这样就能够通过几个shard把整个大的模型训练文件数量cache下来,对外提供大规模的模型训练,而后咱们的前端是减少了proxy,proxy其实外部是保护一张hash映射表的,用户过去的申请其实是通过proxy进行hash的映射查找,而后调配到固定的某一个集群上进行解决,比方过去的一个文件申请通过计算它的hash 映射能够断定hash 映射路由到cluster1下面去,这样其实就能够由cluster1负责,其余key的映射调配到其余cluster上,把数据打散,这样的益处有很多方面:

√ 第一个就是元数据承载能力变大了;
√ 第二个就把申请的压力调配到多个集群下来,整体的qps能力、集群的吞吐能力都会失去相应的晋升;
√ 第三个就是通过这种计划,实践上能够扩大出很多的cluster集群,如果单个集群反对的规模是3-6个亿,那三个集群反对的规模就是9-18亿,如果扩大的更多,对百亿这种规模也能够提供一种反对的解决方案。

以上是咱们对模型进行的一些优化。整个的框架包含稳定性的建设、性能的优化和规模的晋升。
√ 在稳固建设方面:咱们能够把整个集群做FO的工夫管制在30秒以内,如果再配合一些其余机制,比方client端有一些元数据缓存机制,就能够达到一种用户无感知的条件下进行FO,这种成果其实也是用户最想要的,在他们无感知的状况下,底层做的任何货色都能够复原,他们的业务训练也不会中断,也不会有感到任何的谬误,所以这种形式对用户来说是比拟敌对的。
√ 在性能优化方面:单个集群的吞吐曾经造成了三倍以上晋升,整个性能也会晋升上来,能够反对更大并发的模型训练任务。
√ 在模型规模晋升方面:模型训练汇合越来越大,能够把这种模型训练引入进来,对外提供反对。在Alluxio引入蚂蚁适配这些优化之后,目前运行下来对各个方向业务的反对成果都是比拟显著的。另外目前咱们跟开源社区也有很多的单干,社区也给咱们提供很多帮忙,比方在一些比拟焦急的问题上,能够给咱们提供一些解决方案和帮忙,在此咱们表示感谢!想要理解更多对于Alluxio的干货文章、热门流动、专家分享,可点击进入【Alluxio智库】: