Hadoop YARN:调度性能优化实践12

打印 上一主题 下一主题

主题 1047|帖子 1047|积分 3145

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
  背景

YARN作为Hadoop的资源管理体系,负责Hadoop集群上计算资源的管理和作业调度。
美团的YARN以社区2.7.1版本为底子构建分支。目前在YARN上支撑离线业务、及时业务以及机器学习业务。


  • 离线业务重要运行的是Hive on MapReduce, Spark SQL为主的数据仓库作业。
  • 及时业务重要运行Spark Streaming,Flink为主的及时流计算作业。
  • 机器学习业务重要运行TensorFlow,MXNet,MLX(美团点评自研的大规模机器学习体系)等计算作业。
YARN面对高可用、扩展性、稳固性的问题很多。其中扩展性上遇到的最严重的,是集群和业务规模增长带来的调度器性能问题。从业务角度来看,假设集群1000台节点,每个节点提供100个CPU的计算能力。每个使命使用1个CPU,平均执行时间1分钟。集群在高峰期始终有凌驾10万CPU的资源需求。集群的调度器平均每分钟只能调度5万的使命。从分钟级别观察,集群资源使用率是50000/(100*1000)=0.5,那么集群就有50%的计算资源因为调度能力的问题而无法使用。
随着集群规模扩大以及业务量的增长,集群调度能力会随着压力增加而逐渐下降。假设调度能力依然保持稳定,每分钟调度5万个使命,按照5000台节点的规模计算,如果不做任何优化改进,那么集群资源使用率为:50000/(100*5000) = 10%,剩余的90%的机器资源无法被利用起来。
这个问题办理后,集群在有空余资源的情况下,作业资源需求可以快速得到满足,集群的计算资源得到充分地利用。
下文会渐渐将Hadoop YARN调度体系的核心模块展开说明,揭开上述性能问题的根本缘故原由,提出体系化的办理方案,最终Hadoop YARN到达支撑单集群万级别节点,支持并发运行数万作业的调度能力。
整体架构

YARN架构

YARN负责作业资源调度,在集群中找到满足业务的资源,帮助作业启动使命,管理作业的生命周期。
YARN详细的架构设计请参考Hadoop官方文档。
资源抽象

YARN在cpu,memory这两个资源维度对集群资源做了抽象。
  1. class Resource{
  2.   int cpu;   //cpu核心个数
  3.   int memory-mb; //内存的MB数
  4. }
复制代码
作业向YARN申请资源的请求是:List[ResourceRequest]
  1. class ResourceRequest{
  2.   int numContainers; //需要的container个数
  3.   Resource capability;//每个container的资源
  4. }
复制代码
YARN对作业相应是:List[Container]
  1. class Container{
  2.   ContainerId containerId; //YARN全局唯一的container标示
  3.   Resource capability;  //该container的资源信息
  4.   String nodeHttpAddress; //该container可以启动的NodeManager的hostname
  5. }
复制代码
YARN调度架构



YARN调度器
名词解释


  • ResourceScheduler是YARN的调度器,负责Container的分配。
  • AsyncDispatcher是单线程的事件分发器,负责向调度器发送调度事件。
  • ResourceTrackerService是资源跟踪服务,重要负责接收处置惩罚NodeManager的心跳信息。
  • ApplicationMasterService是作业的RPC服务,重要负责接收处置惩罚作业的心跳信息。
  • AppMaster是作业的程序控制器,负责跟YARN交互获取/释放资源。
调度流程

  • 作业资源申请过程:AppMaster通过心跳告知YARN资源需求(List[ResourceRequest]),并取回前次心跳之后,调度器已经分配好的资源(List[Container])。
  • 调度器分配资源流程是:Nodemanager心跳触发调度器为该NodeManager分配Container。
资源申请和分配是异步举行的。ResourceScheduler是抽象类,必要自行实现。社区实现了公平调度器(FairScheduler)和容量调度器(CapacityScheduler)。美团点评根据自身的业务模式的特点,采用的是公平调度器。
公平调度器

作业的构造方式

在公平调度器中,作业(App)是挂载如下图的树形队列的叶子。


队列结构
核心调度流程



核心调度流程

  • 调度器锁住FairScheduler对象,避免核心数据结构辩论。
  • 调度器选取集群的一个节点(node),从树形队列的根节点ROOT开始出发,每层队列都会按照公平战略选择一个子队列,末了在叶子队列按照公平战略选择一个App,为这个App在node上找一块适配的资源。
对于每层队列举行如下游程:

  • 队列预先检查:检查队列的资源使用量是否已经凌驾了队列的Quota
  • 排序子队列/App:按照公平调度战略,对子队列/App举行排序
  • 递归调度子队列/App
例如,某次调度的路径是ROOT -> ParentQueueA -> LeafQueueA1 -> App11,这次调度会从node上给App11分配Container。
伪代码
  1. class FairScheduler{
  2.   /* input:NodeId
  3.    *  output:Resource 表示分配出来的某个app的一个container的资源量
  4.    *  root 是树形队列Queue的根
  5.    */
  6.   synchronized Resource attemptScheduling(NodeId node){
  7.     root.assignContainer(NodeId);
  8.   }
  9. }
  10. class Queue{
  11.   Resource assignContainer(NodeId node){
  12.     if(! preCheck(node) ) return;  //预先检查
  13.       sort(this.children);  //排序
  14.     if(this.isParent){
  15.       for(Queue q: this.children)
  16.         q.assignContainer(node);  //递归调用
  17.     }else{
  18.       for(App app: this.runnableApps)
  19.         app.assignContainer(node);
  20.     }
  21.   }
  22. }
  23. class App{
  24.   Resource assignContainer(NodeId node){
  25.     ......
  26.   }
  27. }
复制代码
公平调度器架构

公平调度器是一个多线程异步协作的架构,而为了包管调度过程中数据的同等性,在重要的流程中加入了FairScheduler对象锁。其中核心调度流程是单线程执行的。这意味着Container分配是串行的,这是调度器存在性能瓶颈的核心缘故原由。


公平调度器架构


  • scheduler Lock:FairScheduler对象锁
  • AllocationFileLoaderService:负责公平战略配置文件的热加载,更新队列数据结构
  • Continuous Scheduling Thread:核心调度线程,不停地执行上节的核心调度流程
  • Update Thread:更新队列资源需求,执行Container抢占流程等
  • Scheduler Event Dispatcher Thread: 调度器事件的处置惩罚器,处置惩罚App新增,App结束,node新增,node移除等事件
性能评估

上文介绍了公平调度器的架构,在大规模的业务压力下,这个体系存在性能问题。从应用层的表现看,作业资源需求得不到满足。从体系模块看,多个模块协同工作,每个模块多多少少都存在性能问题。如何评估体系性能已经可以满足线上业务的需求?如何评估体系的业务承载能力?我们必要找到一个体系的性能目标。因此在谈性能优化方案之前,必要先说一说调度体系性能评估方法。
一般来说,在线业务体系的性能是用该体系可以大概承载的QPS和相应的TP99的延迟时间来评估,而调度体系与在线业务体系不同的是:调度体系的性能不能用RPC(ResourceManager接收NodeManager和AppMaster的RPC请求)的相应延迟来评估。缘故原由是:这些RPC调用过程跟调度体系的调度过程是异步的,因此不论调度性能多么差,RPC相应险些不受影响。同理,不论RPC相应多么差,调度性能也险些不受影响。
业务指标-有用调度

首先从满足业务需求角度分析调度体系的业务指标。调度体系的业务目标是满足业务资源需求。指标是:有用调度(validSchedule)。在生产环境,只要validSchedule达标,我们就以为目前调度器是满足线上业务需求的。
界说validSchedulePerMin表现某一分钟的调度性能达标的情况。达标值为1,不达标值为0。
  1. validPending = min(queuePending, QueueMaxQuota)
  2. if  (usage / total  > 90% || validPending == 0):   validSchedulePerMin = 1 //集群资源使用率高于90%,或者集群有效资源需求为0,这时调度器性能达标。
  3. if (validPending > 0 &&  usage / total < 90%) : validSchedulePerMin = 0;//集群资源使用率低于90%,并且集群存在有效资源需求,这时调度器性能不达标。
复制代码


  • validPending表现集群中作业有用的资源需求量
  • queuePending表现队列中全部作业的资源需求量
  • QueueMaxQuota表现该队列资源最大限额
  • usage表现集群已经使用的资源量
  • total表现集群总体资源
设置90%的缘故原由是:资源池中的每个节点可能都有一小部分资源因为无法满足任何的资源需求,出现的资源碎片问题。这个问题类似linux内存的碎片问题。由于离线作业的使命执行时间非常短,资源很快可以得到回收。在离线计算场景,调度效率的重要性远远大于更准确地管理集群资源碎片,因此离线调度战略暂时没有考虑资源碎片的问题。
validSchedulePerDay表现调度性能天天的达标率。 validSchedulePerDay = ΣvalidSchedulePerMin /1440
目火线上业务规模下,业务指标如下: validSchedulePerMin > 0.9; validSchedulePerDay > 0.99
体系性能指标-每秒调度Container数

调度体系的本质是为作业分配Container,因此提出调度体系性能指标CPS–每秒调度Container数。 在生产环境,只要validSchedule达标,表明目前调度器是满足线上业务需求的。而在测试环境,必要关注不同压力条件下的CPS,找到当前体系承载能力的上限,并进一步引导性能优化工作。
CPS是与测试压力相干的,测试压力越大,CPS可能越低。从上文公平调度器的架构可以看到,CPS跟如下信息相干:


  • 集群总体资源数;集群资源越多,集群可以并发运行的的Container越多,对调度体系产生越大的调度压力。目前每台物理机的cpu、memory资源量差距不大,因此集群总体资源数重要看集群的物理机节点个数。
  • 集群中正在运行的App数;作业数越多,必要调度的信息越多,调度压力越大。
  • 集群中的队列个数;队列数越多,必要调度的信息越多,调度压力越大。
  • 集群中每个使命的执行时间;使命执行时间越短会导致资源释放越快,那么动态产生的空闲资源越多,对调度体系产生的压力越大。
例如,集群1000个节点,同时运行1000个App,这些App分布在500个Queue上,每个App的每个Container执行时间是1分钟。在如许的压力条件下,调度体系在有大量资源需求的情况下,每秒可以调度1000个Container。那么在这个条件下,调度体系的CPS是1000/s。
调度压力模拟器

在线上环境中,我们可以通过观察上文提到的调度体系的指标来看当前调度性能是否满足业务需求。但我们做了一个性能优化战略,不能直接到在线上环境去实行,因此我们必须有能力在线下环境验证调度器的性能是满足业务需求的,之后才能把实行有用的优化战略推广到线上环境。
那我们在线下也搭建一套跟线上规模一样的集群,是否就可以举行调度器性能优化的分析和研究呢?理论上是可以的,但这必要大量的物理机资源,对公司来说是个巨大的成本。因此我们必要一个调度器的压力模拟器,在不必要大量物理机资源的条件下,可以大概模拟YARN的调度过程。
社区提供了开源调度器的压力模拟工具–Scheduler Load Simulater(SLS)。


调度压力模拟器
如上图,左侧是开源SLS的架构图,整体都在一个进程中,ResourceManager模块内里有一个用线程模拟的Scheduler。App和NM(NodeManager)都是由线程模拟。作业资源申请和NM节点心跳采用方法调用。
开源架构存在的问题有:


  • 模拟大规模APP和NM必要开启大量的线程,导致调度器线程和NM/App的模拟线程争抢cpu资源,影响调度器的评估。
  • SLS的Scheduler Wapper中加入了不合理的逻辑,严重影响调度器的性能。
  • SLS为了通用性考虑,没有侵入FairScheduler的调度过程获取性能指标,仅仅从外围获取了Queue资源需求,Queue资源使用量,App资源需求,App资源使用量等指标。这些指标都不是性能指标,无法利用这些指标分析体系性能瓶颈。
针对存在的问题,我们举行了架构改造。右侧是改造后的架构图,从SLS中剥离Scheduler Wapper的模拟逻辑,用真实的ResourceManager代替。SLS仅仅负责模拟作业的资源申请和节点的心跳报告。ResourceManager是真实的,线上生产环境和线下压测环境暴露的指标是完全一样的,因此线上线下可以很直观地举行指标对比。详细代码参考:YARN-7672
细粒度监控指标

利用调度压力模拟器举行压测,观察到validSchedule不达标,但依然不清楚性能瓶颈到底在哪里。因此必要细粒度指标来确定性能的瓶颈点。由于调度过程是单线程的,因此细粒度指标获取的本领是侵入FairScheduler,在调度流程中收罗关键函数每分钟的时间斲丧。目标是找到耗费时间占比最多的函数,从而定位体系瓶颈。例如:在preCheck函数的前后加入时间统计,就可以收集到调度过程中preCheck斲丧的时间。
基于以上的思绪,我们界说了10多个细粒度指标,比力关键的指标有:


  • 每分钟父队列preCheck时间
  • 每分钟父队列排序时间
  • 每分钟子队列preCheck时间
  • 每分钟子队列排序时间
  • 每分钟为作业分配资源的时间
  • 每分钟因为作业无资源需求而耗费的时间
关键优化点

第一次做压测,给定的压力就是当时线上生产环境峰值的压力情况(1000节点、1000作业并发、500队列、单Container执行时间40秒)。颠末优化后,调度器性能提拔,满足业务需求,之后通过预估业务规模增长来调解测试压力,反复迭代地举行优化工作。
下图是性能优化时间线,纵轴为调度性能CPS。


性能优化时间线
优化排序比力函数

在核心调度流程中,第2步是排序子队列。观察细粒度指标,可以很清楚地看到每分钟调度流程总共用时50秒,其中排序时间占用了30秒,占了最大比例,因此首先考虑优化排序时间。
排序自己用的快速排序算法,已经没有优化空间。进一步分析排序比力函数,发现排序比力函数的时间复杂度非常高。
计算复杂度最高的部分是:必要获取队列/作业的资源使用情况(resourceUsage)。原算法中,每2个队列举行比力,必要获取resourceUsage的时间,程序都是现场计算。计算方式是递归累加该队列下全部作业的resourceUsage。这造成了巨大的重复计算量。
优化战略:将现场计算优化为提前计算。
提前计算算法:当为某个App分配了一个Container(资源量界说为containerResource),那么递归调解父队列的resourceUsage,让父队列的resourceUsage += containerResource。当释放某个App的一个Container,同样的原理,让父队列resourceUsage -= containerResource。 利用提前计算算法,队列resourceUsage的统计时间复杂度低落到O(1)。
优化效果:排序相干的细粒度指标耗时明显下降。


优化排序比力函数效果
红框中的指标表现每分钟调度器用来做队列/作业排序的时间。从图中可以看出,颠末优化,排序时间从每分钟30G(30秒)下降到5G(5秒)以内。 详细代码参考:YARN-5969
优化作业跳过期间

从上图看,优化排序比力函数后,蓝色的线有明显的增加,从2秒增加到了20秒。这条蓝线指标含义是每分钟调度器跳过没有资源需求的作业耗费的时间。从时间占比角度来看,目前优化目标是减少这条蓝线的时间。
分析代码发现,全部队列/作业都会到场调度。但其实很多队列/作业根本没有资源需求,并不必要到场调度。因此优化战略是:在排序之前,从队列的Children中剔除掉没有资源需求的队列/作业。
优化效果:这个指标从20秒下降到险些可以忽略不计。详细代码参考:YARN-3547


优化作业跳过期间
这时,从上图中可以明显看到有一条线呈现上升趋势,并且这个指标占了整个调度时间的最大比例。这条线对应的指标含义是确定要调度的作业后,调度器为这个作业分配出一个Container耗费的时间。这部分逻辑平均执行一次的时间在0.02ms以内,并且不会随着集群规模、作业规模的增加而增加,因此暂时不做进一步优化。
队列并行排序优化

从核心调度流程可以看出,分配每一个Container,都必要举行队列的排序。排序的时间会随着业务规模增加(作业数、队列数的增加)而线性增加。
架构思索:对于公平调度器来说,排序是为了实现公平的调度战略,但资源需求是时时候刻变革的,每次变革,都会引起作业资源使用的不公平。纵然分配每一个Container时都举行排序,也无法在整个时间轴上告竣公平战略。
例如,集群有10个cpu,T1时候,集群只有一个作业App1在运行,申请了10个cpu,那么集群会把这10个cpu都分配给App1。T2时候(T2 > T1),集群中新来一个作业App2,这时集群已经没有资源了,因此无法为App2分配资源。这时集群中App1和App2对资源的使用是不公平的。从这个例子看,仅仅通过调度的分配算法是无法在时间轴上实现公平调度。
目前公平调度器的公平战略是包管集群在某一时候资源调度的公平。在整个时间轴上是必要抢占战略来增补到达公平的目标。 因此从时间轴的角度考虑,没有必要在分配每一个Container时都举行排序。
综上分析,优化战略是排序过程与调度过程并行化。要点如下:

  • 调度过程不再举行排序的步调。
  • 独立的线程池处置惩罚全部队列的排序,其中每个线程处置惩罚一个队列的排序。
  • 排序之前,通过深度克隆队列/作业中用于排序部分的信息,包管排序过程中队列/作业的数据结构稳定。


并行排序优化
优化效果如下:
队列排序效率:利用线程池对2000个队列举行一次排序只必要5毫秒以内(2ms-5ms),在一秒内至少可以完成200次排序,对业务完全没有影响。
在并行运行1万作业,集群1.2万的节点,队列个数2000,单Container执行时间40秒的压力下,调度CPS到达5万,在一分钟内可以将整个集群资源打满,并连续打满。


并发作业数


作业资源需求量


集群资源使用率
上图中,15:26分,pending值是0,表现这时集群目前全部的资源需求已经被调度完成。15:27分,resourceUsage到达1.0,表现集群资源使用率为100%,集群没有空闲资源。pending值到达4M(400万 mb的内存需求)是因为没有空闲资源导致的资源期待。
稳固上线的战略

线下压测的结果非常好,最终要上到线上才能告竣业务目标。然而稳固上线是有难度的,缘故原由:


  • 线上环境和线下压测环境中的业务差别非常大。线下没问题,上线不一定没问题。
  • 当时YARN集群只有一个,那么调度器也只有一个,如果调度器出现异常,是整个集群的灾难,导致整个集群不可用。
除了通例的单元测试、功能测试、压力测试、设置报警指标之外,我们根据业务场景提出了针对集群调度体系的上线战略。
在线回滚战略

离线生产的业务高峰在破晓,因此破晓服务出现故障的概率是最大的。而破晓RD同砚接到报警电话,执行通常的服务回滚流程(回滚代码,重启服务)的效率是很低的。并且重启期间,服务不可用,对业务产生了更长的不可用时间。因此我们针对调度器的每个优化战略都有参数配置。只必要修改参数配置,执行配置更新命令,那么在不重启服务的情况下,就可以改变调度器的执行逻辑,将执行逻辑切换回优化前的流程。
这里的关键问题是:体系通过配置加载线程更新了调度器某个参数的值,而调度线程也同时在按照这个参数值举行工作。在一次调度过程中可能多次检察这个参数的值,并且根据参数值来执行相应的逻辑。调度线程在一次调度过程中观察到的参数值发生变革,就会导致体系异常。
处置惩罚办法是通过复制资源的方式,避免多线程共享资源引起数据不同等的问题。调度线程在每次调度开始阶段,先将当前全部性能优化参数举行复制,确保在本次调度过程中观察到的参数不会变更。
数据主动校验战略

优化算法是为了提拔性能,但要注意不能影响算法的输出结果,确保算法精确性。对于复杂的算法优化,确保算法精确性是一个很有难度的工作。
在“优化排序比力时间”的研发中,变更了队列resourceUsage的计算方法,从现场计算变更为提前计算。那么如何包管优化后算法计算出来的resourceUsage是精确的呢?
纵然做了单元战略,功能测试,压力测试,但面对一个复杂体系,依然不能有100%的把握。 别的,未来体系升级也可能引起这部分功能的bug。
算法变更后,如果新的resourceUsage计算错误,那么就会导致调度战略一直错误执行下去。从而影响队列的资源分配。会对业务产生巨大的影响。例如,业务拿不到原来的资源量,导致业务延迟。
通过原先现场计算的方式得到的全部队列的resourceUsage一定是精确的,界说为oldResourceUsage。 算法优化后,通过提前计算的方式得到全部队列的resourceUsage,界说为newResourceUsage。
在体系中,定期对oldResourceUsage和newResourceUsage举行比力,如果发现数据不同等,说明优化的算法有bug,newResourceUsage计算错误。这时体系会向RD发送报警通知,同时主动地将全部计算错误的数据用精确的数据替换,使得错误得到及时主动修正。
总结与未来展望

本文重要介绍了美团点评Hadoop YARN集群公平调度器的性能优化实践。

  • 做性能优化,首先要界说宏观的性能指标,从而可以大概评估体系的性能。
  • 界说压测必要观察的细粒度指标,才能清晰看到体系的瓶颈。
  • 工欲善其事,必先利其器。高效的压力测试工具是性能优化必备的利器。
  • 优化算法的思绪重要有:低落算法时间复杂度;减少重复计算和不必要的计算;并行化。
  • 性能优化是永无止境的,要根据真实业务来合理预估业务压力,渐渐开展性能优化的工作。
  • 代码上线需审慎,做好防御方案。
单个YARN集群调度器的性能优化总是有限的,目前我们可以支持1万节点的集群规模,那么未来10万,100万的节点我们如何应对?
我们的办理思绪是:基于社区的思绪,设计适合美团点评的业务场景的技术方案。社区Hadoop 3.0研发了Global Scheduling,完全颠覆了目前YARN调度器的架构,可以极大进步单集群调度性能。我们正在跟进这个Feature。社区的YARN Federation已经渐渐美满。该架构可以支撑多个YARN集群对外提供统一的集群计算服务,由于每个YARN集群都有自己的调度器,这相称于横向扩展了调度器的个数,从而进步集群整体的调度能力。我们基于社区的架构,结合美团点评的业务场景,正在不停地美满美团点评的YARN Federation。

from:
Hadoop YARN:调度性能优化实践 - 美团技术团队
日常开发Guava提效工具库核心实用指南梳理_guava string转list-CSDN博客
异步处置惩罚优化:多线程线程池与消息队列的选择与应用_模版模式使用-CSDN博客
接口性能优化宝典:办理性能瓶颈的战略与实践_前端网站页面的搭建-CSDN博客
日常开发Guava提效工具库核心实用指南梳理_guava string转list-CSDN博客

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

王國慶

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表