vlambda博客
学习文章列表

小米Hadoop YARN平滑升级3.1实践




 小米所有业务的离线和流式计算资源都是基于Hadoop YARN进行管理的。
随着业务快速发展,集群规模成倍增长,带来了单集群调度性能和跨机房部署等挑战。
为了更好地应对这些挑战,经过调研我们决定从2.6版本升级到3.1版本和社区保持同步,之后再基于社区在扩展性、性能等方面做的工作进行二次开发
往期文章回顾:
背景

小米之前生产环境的Hadoop YARN是基于社区2.6版本修改的内部版本,我们最大规模集群已经数千台,而且还在不断增长。在目前2.6版本,我们主要面临两个问题:

  • 滞后社区多个大版本, 很多新特性以及bug修复没法使用或者需要重新开发;
  • 集群规模增长很快,经历了多次机房迁移,当前版本不能很好地支持跨机房部署方案来实现作业透明迁移;

我们调研3.1过程中发现,基于YARN Federation(YARN-2915)的跨机房部署方案已经很成熟。同时,为了和社区保持同步,减少代码的维护成本。我们决定升级到Hadoop 3.1(注:在我们开始调研的时候3.2还没release)。

在升级到Hadoop 3.1之后,我们会基于YARN Federation这个特性来落地跨机房部署方案。同时,在3.1版本我们会和社区一起推进落地基于公有云的Auto Scaling方案。

目标与挑战

小米Hadoop YARN在生产环境有数十个集群(包括国内和海外),服务于小米所有业务线,包含大量的批处理和流式计算作业(>10w/天)。本次升级到Hadoop 3.1希望能做到对业务透明,尽量减少对业务的影响:

  • 升级期间,不需要停服;
  • 升级期间历史作业不失败;
  • 升级期间可以持续提交新作业;
  • 升级期间,作业日志能够正常查看;

Hadoop YARN的架构组成包括ResourceManager(简写RM)、NodeManager(简写NM)、HistoryServer、ProxyServer等多个组件,这些组件之间需要进行RPC通信,如下图所示:

小米Hadoop YARN平滑升级3.1实践
图1-Hadoop YARN各个组件通信
由于Hadoop YARN组件很多,集群规模也很大,为了控制风险,不能一次性把所有组件都升级到3.1版本。 我们面临的挑战是在多个模块不同版本共存的时候,如何保障上层各类计算框架(Spark、Flink、MapReduce等)调度的作业不受影响。
升级过程

>>>>

patch合并/重构

之前我们内部一直维护的是基于社区2.6修改的内部版本,我们实现了很多patch来满足业务场景。 为了升级到3.1版本,我们首先要做的就是把内部patch合并到社区的3.1版本。 由于版本跨度很大,这一步我们做了大量的重构工作,这期间主要通过单元测试来保障代码质量。
我们内部的工作主要集中在以下几个方面:
  • 稳定性优化,如基于ZK的client配置管理,实现了RM等服务的平滑迁移( YARN-9605 ),NM隔离优化( YARN-9977 ),HistoryServer稳定性优化( YARN-9973 )等;
  • 调度优化,如延时调度,缓存resource usage提升排序效率,事件处理优化( YARN-9979 )等;
  • 易用性优化,如支持MR作业查看实时jstack信息( YARN-10069 ),支持ui kill app,支持MySQL的StateStore等;
  • 多集群管理和多租户管理,我们主要进行了资源管理服务产品化,提供统一的infra-client和web化的资源管理(支持计量计费等);
目前,这些工作已经陆续往社区提交,为我们后续升级版本减轻工作量,同时也希望我们的解决方案能给社区其他成员提供帮助。

>>>>

兼容性/回归测试

前面提到,我们patch合并重构期间主要是通过单元测试来保证代码质量。 但是大量patch合并之后,我们必须对整体功能进行完整的回归测试。
同时,在图1中我们看到Hadoop YARN涉及的RPC通信模块很多,版本升级过程中,需要保证各个模块之间通信协议的兼容性。 这里,重点讲一下我们如何进行兼容性测试的。
兼容性测试第一块是Hadoop本身各个服务模块之间的通信兼容,主要设计的case如图2所示:
小米Hadoop YARN平滑升级3.1实践
图2-Hadoop YARN组件兼容性测试
当然,兼容性相关还有一个比较重要的测试就是针对计算框架的测试。 这里我们主要针对内部使用的如下框架进行了测试:
  • Hive 1.2;
  • Hadoop MapReduce 2.6/3.1;
  • Spark 1.6/2.1/2.3;
  • Flink 1.8;
在测试过程,也需要考虑不同版本和不同部署模式的HDFS,比如我们内部有2.6的Federation集群和非Federation集群。 另外,考虑到我们目前访问HBase的作业大部分是通过Spark实现,我们主要测试了Spark作业访问HBase的场景。

>>>>

调度器测试

小米之前使用的调度器是基于社区2.6版本修改的FairScheduler。 在和社区交流过程发现,社区后续的发展方向主要在CapacityScheduler ( YARN-5864 ),并且在Hadoop 3.x中CapacityScheduler对调度性能、资源利用率等方面进行了很多优化。 所以在升级3.1之后我们有一个比较大的改动是从FairScheduler切换到CapacityScheduler。 这里主要面临两个问题:
  • 线上生产集群的FairScheduler相关队列配置已经使用了很长一段时间,需要平滑切换到CapacityScheduler;
  • 我们的资源管理服务之前是针对FairScheduler设计的,需要对CapacityScheduler进行适配;
其中比较重要的是问题1,这个问题在社区会议的时候提出来了,之后社区也有相关issue跟进( YARN-9698 )。 我们内部的解决办法是把重要配置进行了梳理,实现一个工具基于FairScheduler的配置自动化地生成对应的CapacityScheduler配置。 这里几个比较重要的配置提一下:
 
   
   
 
maximum-am-resource-percentuser-limit-factorintra-queue-preemption.disable_preemptiondisable_preemptionmaximum-capacity
其中user-limit-factor和maximum-am-resource-percent在FairScheduler语义不太一样或者是没有实现。 我们针对调度器的测试主要是通过线上FairScheduler配置生成CapacityScheduler配置来启动测试RM,然后进行验证。 目前,针对调度器的性能测试我们也探索了SLS工具。
针对CapacityScheduler我们提交了一些patch给社区: YARN-7621 YARN-9748 YARN-9709 等。

>>>>

升级/回滚方案

经过上面的单元测试、兼容性测试、调度器测试之后,我们设计和演练了升级方案。 最后确定的主要步骤如下:
  1. 准备好回归测试作业(包括Hive/MR/Spark等),作业类型包含基本的TeraSort、WordCount以及一些用户的作业
  2. 升级资源管理服务
    1. 支持同时更新FairScheduler和CapacityScheduler的配置,当CapacityScheduler出现问题的时候可以直接回滚到FairScheduler
  3. 升级控制节点(RM/HistoryServer/ProxyServer)
    1. RM主节点使用3.1版本的CapacityScheduler,备节点使用2.6版本的FairScheduler,当调度出现问题的时候,可以做主备切换进行恢复
    2. 基于回归测试作业进行验证,同时确认日志查看、主备跳转是否正常
  4. 升级Hadoop客户端配置和包
    1. 升级测试机器,验证回归测试作业是否正常运行
    2. 升级监控机器,验证监控作业是否正常运行
    3. 分批逐步升级作业调度机器,观察用户作业是否正常运行
  5. 升级Hive到兼容3.1的版本
    1. 部署一个兼容3.1版本的Hive实例,然后验证回归作业和线上部分历史作业
    2. 分批逐步升级其他Hive实例,观察用户查询是否正常运行
  6. 分批升级NM(注: 我们修改了2.6版本NM的recovery模块,支持直接从3.1回滚到2.6)
    1. 我们会按照5%->25%->50%->75%->100%的灰度策略对NM进行操作
    2. 每步更新都会对回归测试作业进行验证
在升级过程中,我们主要通过作业级别、队列级别、集群级别的监控报警来帮助我们及时发现问题。
问题&解决
在升级测试、演练和执行落地过程中,我们遇到一些问题:

>>>>

NM回滚2.6版本异常

测试回滚NM的时候,发现如下异常,主要是3.1版本的recovery相关状态多了很多字段
 
   
   
 
2019-xx-xx,17:06:12,797 FATAL org.apache.hadoop.yarn.server.nodemanager.NodeManager: Error starting NodeManagerorg.apache.hadoop.service.ServiceStateException: java.io.IOException: Unexpected container state key:ContainerManager/containers/container_e36_1558337587778_0027_01_000002/starttime
修复办法就是在2.6版本实现类似逻辑或者是直接兼容一下。

>>>>

MR RPC协议修改导致作业执行异常

Hadoop Mapreduce在3.1版本针对TaskUmbilicalProtocol做了一些改动,如果是2.6和3.1进行通信,会出现下面问题。 这里解决办法是通过在client指定classpath保证单个作业依赖的版本是一致的。
 
   
   
 
2019-xx-xx 16:49:49,306 WARN [main] org.apache.hadoop.mapred.YarnChild: Exception running child : org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.ipc.RPC$VersionMismatch): Protocol org.apache.hadoop.mapred.TaskUmbilicalProtocol version mismatch. (client = 19, server = 21)

>>>>

FileOutputCommitter版本改变导致数据丢失

FileOutputCommitter在3.1版本增加了新的commit算法,并且默认是不写临时目录了。 而在2.6版本,默认的commit算法是先写临时目录最后原子的move到最终输出目录。 当NM版本是2.6和3.1共存的时候,我们遇到了Spark作业结果数据比预期少很多的问题。
解决办法很简单,先调整代码的默认算法:
mapred-default.xml:
 
   
   
 
<name>mapreduce.fileoutputcommitter.algorithm.version</name><value>1</value>
FileOutputCommitter:
 
   
   
 
public static final String FILEOUTPUTCOMMITTER_ALGORITHM_VERSION = "mapreduce.fileoutputcommitter.algorithm.version";public static final int FILEOUTPUTCOMMITTER_ALGORITHM_VERSION_DEFAULT = 1;

>>>>

日志配置文件不存在

3.1和2.6在生成launch container脚本的时候对于log目录的设置存在差异。
 
   
   
 
log4j:ERROR setFile(null,true) call failed.java.io.FileNotFoundException: /home/work/hdd3/yarn/c4prc-preview/nodemanager/application_1559618566050_0070/container_e18_1559618566050_0070_01_000001 (Is a directory)

>>>>

容量调度器配置不对

容量调度器对于<0,0>的配置是不识别的,并且会直接抛异常导致RM启动失败。
 
   
   
 
2019-06-25,16:07:19,266 FATAL org.apache.hadoop.yarn.server.resourcemanager.ResourceManager: Error starting ResourceManagerjava.lang.IllegalArgumentException: Parent queue 'root.production' and child queue 'root.production.xiaoqiang_group' should use either percentage based capacityconfiguration or absolute resource together for label
当然,还有很多其他问题这里没有展示。 部分修复我们已经提交社区比如: ( YARN-9693 )、( YARN-9689 ),后续其他修复我们也会提交社区。
后续计划
2019年我们已经完成了国内外数十个集群的升级,2020年Q1我们会完成最后一个公共集群的升级。 从成本和扩展性考虑,我们下一步会在如下几个方向继续探索:
  • 落地Yarn Federation支持超大规模联邦集群,支持同城跨机房部署(>1w台);
  • 在海外落地基于公有云的Auto Scaling方案( YARN-9548 ),系统化地优化公有云集群成本;
  • 探索落地离在线混部的方案,打通在线/离线计算资源;
致谢
感谢计算平台SRE组同学以及存储团队HDFS同学在升级期间的给力支持! (目前我们存储团队也已经推进多个HDFS集群升级到了Hadoop 3.1,期待他们的分享)
关于我们
小米云平台计算平台团队,负责为小米集团各业务线提供高品质的弹性调度和计算服务。 包括离线平台(Spark,Hadoop Yarn,Kylin,Doris等),流式平台(Kafka,Flink及自研Talos等),弹性平台(Docker,Kubernetes等)。 武汉团队主要负责Kylin、Druid等OLAP引擎开发。 北京武汉均有职位,欢迎感兴趣的小伙伴加入~ 联系方式: [email protected]
参考
[1] FS Migration CS
https://issues.apache.org/jira/secure/attachment/12979377/FS-CS%20Migration.pdf
[2] YARN Federation
https://issues.apache.org/jira/browse/YARN-2915
[3] Migrating Hulu’s Hadoop Clusters to a New Data Center
https://medium.com/hulu-tech-blog/migrating-hulus-hadoop-clusters-to-a-new-data-center-part-one-extending-our-hadoop-instance-b88c4bda61bc
[4] Hydra: a federated resource manager for data-center scale analytics
https://www.microsoft.com/en-us/research/uploads/prod/2018/12/NSDI19_paper159_CR.pdf
[5] Make YARN work well in elastic cloud environments
https://issues.apache.org/jira/browse/YARN-9548


文末福利



评论区获赞数量最多的粉丝将获得小米90分双肩背包一个


我就知道你“在看”