在这个降本增效的时代,大数据作为Infra成本中的重要构成部分,如何降低大数据场景的Infra成本,是数据平台团队必须要考虑的事情。H公司的混部方案,在行业中较为先行,在2020年即完成了落地,取得了很好的收益,本篇文章即是对该方案的介绍。
我们首先从成本公式来看:
成本=单价*量
要降低成本,需要在“单价”和“量”上做文章。从数据平台团队的视角来看,“量”意味着需要对业务进行治理,优化用户的使用行为,需要用户紧密配合,如果不是从上至下来推动,实施起来会比较困难,也容易受到挑战。而“单价”,则是平台团队可以闭环的,因此我们考虑优先从“单价”着手优化。
大数据的成本,往往由存储和计算组成。优化存储的单价,往往是采用冷热分层,纠删码等方案来实施,该部分内容可以参考“在hadoop2的环境中如何落地hdfs ec”,而本篇文章,重点介绍优化算力的单价,算力单价的组成,其公式可以简化为:
算力单价=单核单价/利用率/计算性能
从该公式中,我们可以降低算力的综合单价,比如使用AMD CPU,也可以通过调度提高CPU利用率,还可以通过计算框架提高计算的性能。我们这儿介绍的离在线混部,分时复用,实际上优化的是“利用率”这个因子,各位可以根据公司自身的实际事情情况,确定优化哪个因子会更为合适。
H公司作为互联网垂直领域的Top1,Infra成本一直都格外看中,在2020年,就将离在线混部分时复用资源提上了日程,经过大半年的能力研发和落地,在2021年的时候,大数据的大部分离线算力来自于在线业务闲时算力的复用,这批服务器的全天CPU利用率从20-%,提高到50+%,总量在十万core的级别,节省了大量的算力成本。
为了能够将宿主机的资源在不同的时间段内,将其分配给不同的业务,一般有两种手段:弹性扩缩和资源混部。
弹性扩缩:指当某个业务的资源需求下降时,将该业务的部分副本Pod下掉,从而将资源释放回容器大池子,其他业务再从容器平台申请这些资源的使用。在离在线的业务场景下,就是在线业务在凌晨释放资源,而离线业务在凌晨申请资源,到白天的时候再反过来。为了避免离在线业务之间的相互影响,由容器平台在资源调度上,保证单台宿主机要么只有离线业务的Pod,要么只有在线业务的Pod,不存在混合部署。相当于在整台宿主机上分时段用潮汐的模式去做算力交付。
混部:指的是离线和在线业务的pod还是保留在宿主机上,通过一些技术手段,将宿主机的资源在离在线pod之间做动态的调配,这种动态调配,可以是Pod释放掉之后再重新申请,也可以是pod保留不变,容器平台在底层调整pod的资源大小,为了避免pod的启停对业务产生影响,后者的模式会更为合适。
弹性扩容和混部这两种模式各有利弊:
弹性扩缩模式:好处在于释放资源最彻底的,因为pod都关掉了,再者不会对对方场景产生稳定性的影响,减少故障发生。缺点在于不太好大面积的落地,主要原因如下:
某些在线应用就一个副本,没法缩容
某些业务的pod缩容掉之后,第二天再扩容时,内存中的数据需要重新预热,这块需要业务配合进行改造,改造成本高
把pod缩容掉之后,万一出现紧急的偶发事件,通过立即扩容来响应,响应速度上达不到要求。
综合上面的诸多因素,所以一般例如在线业务这类高保障性的业务,还是希望能够按照业务的峰值流量来保留pod,而不是每天踩钢丝似的将其缩容掉。但也有些业务场景,保障要求相对没那么高,比如推荐这类,资源需求量大,同时消耗资源的服务也较为集中,改造起来相对成本低一些,并且业务的鲁棒性较高,业务自身有做容错的措施,能够承受些风险。针对这类服务,可以圈定一批服务器,来和离线业务以扩缩容的方式做潮汐算力。
混部模式:采用保留Pod,由容器平台去做Pod资源的动态调配,好处在于几乎不需要在线业务研发和SRE团队参与进来,核心工作在容器平台和数据平台团队,从而大幅降低了实施的工作范围,非常适合产品已经成熟,没动力改造历史服务的场景。
当然可以同时使用两种模式,针对清爽的应用,使用弹性扩缩的模式,比如简单的无状态的web服务;针对历史旧债严重的,则采用混合的模式。在资源利用率和业务改造成本之间取得最佳平衡。
混部,存在两种目标,这儿有必要先阐述一下,他们两者从资源利用方式的维度上看,有明显的不同。
按资源类型拆分:
这是用的最多的方式,解决宿主机上各种类型资源的使用,将资源类型需求不一样的服务混合部署在一起,尽量拉高每种类型资源的利用率,比如有些服务重CPU,有些服务重内存,还有些服务重网络或者重磁盘,把他们相互较差混部在同一台宿主机上,从而尽量把每种类型的资源都利用起来。这是从资源类型的角度去混用,没有考虑到离线业务和在线业务对资源使用时间错峰的特性,所以这种模式,不属于严格意义上的离在线混部。并且该模式,还有一个缺点就是申明之后,剩下的碎片较多,所以资源利用率也不会很高。
按时间拆分:
在离在线混部的场景下,我们是从时间维度去看,在时间片上把资源分给不同的应用。根据宿主机物理CPU的真实负载,对Pod做分钟级的资源扩缩容,不用考虑宿主机上被“申明走”的资源,这种方式有如下特点:
大幅提高资源的利用率:资源虽然被申明走了,但如果当前没有使用,也会被利用起
在线业务的稳定性保障:通过实施监控宿主机负载,和离线Pod协调,对大数据任务进行驱逐,分钟内快速降低负载,保障在线业务稳定
计费逻辑:在线业务可以适当调高Pod申明的资源上限,从而应对业务突然出现的峰值流量冲击,从公司层面看,即便申明的资源没有用上,也会被离线业务所使用。可以在计费逻辑上,做些适当调整,引导业务对这种资源模式的使用,如按照CPU Time计费,凌晨CPU大幅降价等手段。
整个技术实现,需要容器平台和大数据平台相互配合,分成上下两层。底层容器平台以Pod的方式交付存储和算力,而上层的数据平台,主要是针对混部模式下,异构的弹性的资源特性,在任务调度上做出相应的适配,从而一起在保障离在线业务各自稳定性的前提下,提高资源的利用率。
自动交付:大数据的hdfs pod和yarn pod不在是由数据平台团队走API去主动申请,而是由容器团队,根据公司整体的资源规划,以及当前机型配置,结合大数据场景的需求,使用大数据团队提供的镜像,在中心机房自动交付hdfs pod和yarn pod。容器平台首先除去部署着有例如数据库、kafka这种有状态高敏感服务的宿主机,其他所有服务器上自动交付YARN Pod,如果宿主机有SATA盘,同时交付hdfs pod。
本地存储的需求:大数据的MR任务在计算过程中需要用到本地磁盘,但先前在线业务使用的服务器,大多是计算型,本地存储的能力非常弱。考虑到在线业务的稳定性,离线计算和在线业务不能使用同一张SATA盘,所以导致这些机器上的离线任务无存储可用,针对该问题,采用两种方式解决:
a、spark任务使用rss服务,避免对本地盘的需求;
b、hive任务,如果宿主机上有SSD,容量允许的情况下,离在线可以共用SSD,否则容器挂载单独的普通云盘(ceph)给MR使用。同时在大数据的任务调度系统和YARN的调度器中,针对任务的磁盘的需求进行任务画像,对于磁盘需求量大的任务,尽量调度到具有SATA本地盘的YARN Node上去。
Yarn Pod对hdfs Pod的本地读取:原本hdfs namenode在返回hdfs block location时,会优先返回和DFSClient同一台服务器的datanode,从而减少跨主机复制数据所产生的内网流量,而做了hdfs和yarn的容器化改造之后,hdfs和yarn分属不同的pod ip,上面所描述的优化便失效了,该功能对于平台全局的配置或lib jar很有用,因为这类文件的副本数非常多,并且每个task都需要用到,所以产生的流量非常大,有必要对其进行读取优化,为了支撑该逻辑,我们进行了改造:
1、订阅容器平台的pod变更事件,收集宿主机Ip和Pod Ip的映射关系,将其保存到分布式文件系统中。
2、在namenode中,定时将上述映射关系cache到namenode中
3、在namenode中,修改返回block location处的代码,根据pod ip调整location列表中的datanode location顺序,从而实现优先读取同宿主机的block。
在容器平台中,离线业务的YARN pod是个另类的存在。容器平台会实时监听宿主机上物理CPU的负载情况:
如果CPU高载:则触发驱逐逻辑,给YARN Pod发送驱逐事件,YARN Pod接收到该事件之后,由YARN根据job优先级进行kill task;等一分钟之后,如果CPU负载依然高载,容器平台则会直接驱逐YARN Pod。这种方式的好处是保障在线业务对CPU高优使用权的前提下,又尽量减小了对离线任务的影响
如果CPU低载:容器会动态增大YARN Pod的CPU,同时通知YARN进行资源扩缩容,该服务会调用YARN ResourceManager的API,动态调整YARN Node的VCore和VMem值,从而实现YARN Node的资源扩容。反之缩容也是如此,只是缩容的时机往往是容器平台根据先前宿主机的资源利用情况进行预测,提前触发缩容,降低因为紧急缩容对业务稳定性产生的影响;
扩缩容预案:容器平台也会根据在线业务在时间段上使用资源的时间分布情况,预先对资源进行适当的扩缩,如凌晨前和次日上班前分别进行针对离线业务的扩容和缩容,或是在比赛之前,提前对离线进行缩容,压制其对资源的使用,优先保障赛事。
大数据和在线业务,在鲁棒性上差异巨大,大数据的分布式系统,往往都有自己的容灾方案,所以对资源异常不是很敏感,而在线业务则恰恰相反。所以在大数据场景中,我们一般使用“尽量用”的思路,这种使用模式,就容易对同一台宿主机上的其他在线业务产生影响,所以对资源的隔离份外重要。离线场景中的hdfs pod和yarn pod,采用了不同的隔离方案。
Hdfs Pod:
hdfs属于重IO的服务,在磁盘上,为其固定宿主机上的SATA盘,避免和其他服务争抢磁头;在CPU上,使用cpu set的方式,而非share的模式,固定为其hdfs2.7 pod分配4core,hdfs3 pod分配6core,之所以hdfs3多2core,因为我们绝大部分数据都用ec模式存储,而当ec数据损坏后,数据恢复的计算发生在datanode,所以我们为其多分了2core。根据实际情况,我们凌晨高峰时,cpu的平均利用率在10%左右,因此是够用的。
Yarn Pod:
Yarn pod的cpu和磁盘方案,前面已经有章节进行了介绍,不再在此赘述。在网络上,hdfs和yarn两个pod共享宿主机的离线带宽包,让二者进行带宽争抢,该模式相比各自为其分配带宽,带宽的利用率会更高。
混部环境下交付的YARN Pod,其规格变得非常的“凌乱”,大数据系统需要去适应这类资源,否则这些资源就无法很好的利用。
这类资源具有如下特征:
规格杂乱:宿主机时刻将其剩余的物理CPU资源给到yarn Pod,因此每个Pod的Cpu数,CPU和Memory之间的比值,都是不一样的
规格动态:Yarn Pod的CPU和内存,随时都可能发生改变
生命期随机:为了保障在线业务的稳定性,容器可能会驱逐yarn pod中的task,甚至整个pod。
针对上述特征,在大数据上需要做差异性调度,这种差异性主要体现在“任务对资源的真实需求”,以及“任务失败对业务价值的影响”,从这两个维度,我们会对任务进行画像。其中任务对资源的真实需求,来自于调度系统中,每次任务执行所采集到的counter信息;而任务失败对业务的影响,主要是看该任务是否处于基线调度的高优链路之上。
同时,我们针对yarn node代表的资源也进行画像,一是标识出每个node每类资源的情况,特别是“是否有本地盘”,二是从资源稳定性标识出node被回收的概率,有一批服务器,属于大数据专用,这批服务器上的Pod不会被驱逐,在Yarn中使用Label标识出来。
然后我们结合任务画像和资源画像做任务调度,调度的目的,一是尽量提高资源利用率,二是提高离线任务的稳定性。因此对本地磁盘没需求的任务,会调度到缺少盘的yarn pod上去。将“任务失败对业务价值的影响”大的任务,优先调度到更稳定的yarn node上面去。
从在线业务的稳定性和大数据任务的稳定性两个视角观察,因为容器平台对在线业务使用前述诸多方案做了足够保护,因此对在线业务没有实质影响。同时,离线大数据针对高优任务,以及yarn appmaster,优先调度到高稳定性资源上,所以从被驱逐所导致的task kill来分析,实际的kill率不到十万分之一,很好的对离线业务做了保障。
上述就是H公司在离线在混部场景下的主要方案,早在2021年的行业大会上便做过分享,如有需要细聊的,欢迎给作者留言