Hadoop笔记(5)HA和联邦机制

前面我们已经介绍过了,Hadoop内部有两个master/slave架构,分别是:namenode+datanode,resourcemanager+nodemanager,分别对应Hadoop的两个核心组件Hdfs和Yarn。你可能已经发现了问题,这两个架构都是单点的,也就是说只要namenode/resourcemanager宕机,那么整个集群就不能工作了,即使可以恢复数据,但是在生产系统中也是不允许的。本文将介绍Hadoop为了解决单点故障问题的HA设计。阅读本文内容,建议先了解ZooKeeper的相关内容。

1. Hadoop HA

Hadoop HA是在Hadoop2才引入的,目的就是为了解决namenode和resourcemanager的单点故障问题,我们首先介绍namenode的HA实现机制,了解了namenode的HA,再了解resourcemanager的HA实现就比较简单了。

1.1 Hdfs HA

解决单点故障问题的最好方法自然就是引入备用节点,当活跃(active)的master挂掉的时候,备节点(standby)能够及时的承担起master的责任。方向知道了,怎么实现呢?如果你已经了解ZooKeeper,应该早已想到怎么实现了,因为这就是ZooKeeper做主从选举的典型应用。图1是两个namenode分别处于active和standby状态下的结构图,当然也可以配置多于两个namenoed,工作机制一样,唯一的区别就是多namenode的情况下,一旦active挂掉,其余的standby需要抢主(关于抢主的实现,可以阅读另一篇关于zookeeper的文章),如果只有一个standby,自然就不需要抢了。

Hadoop笔记(5)HA和联邦机制
图1 Hdfs HA结构

每个namenode节点上都有一个zkfc(zookeeper failover controller)进程,可以理解为一个zookeeper客户端。active namenode会在zookeeper上创建一个ephemeral类型的znode,其他standby只需注册监听这个znode(或者父节点),这样一旦active namenode宕机,znode就会被删除,所有standby节点就会感知到,重新发起抢主流程选出新的active节点就可以了,抢主失败的standby还是standby,具体实现可以参考zookeeper篇内容,datanode会向所有的namenode发送心跳包。

节点切换的功能我们已经实现了,但是还有一个重要功能我们没有实现,就是元数据文件的管理问题。在单namenode的情况下,我们知道元数据信息分为三种:内存中的一份完整的元数据信息,保存在磁盘中的大多数元数据信息fsimage文件,以及保存在edits文件中的少部分元数据信息。namenode为了提高元数据的读写效率,创建了一个edits_inprogress文件,用于实时记录当前最新的元数据变化信息,然后由secondary namenode不断地合并edits文件到fsimage中。那么在HA情况下,我们怎么解决多namenode元数据信息的同步呢?而且要确保元数据信息不丢失。为此,Hadoop引入了一个分布式文件系统——Quorum Journal Manager,简称QJM,不要惊讶,Hadoop自身就是一个分布式文件系统,但是它也确实引入了另一个分布式文件系统协助自己工作。QJM是一个比Hadoop轻量许多的分布式系统,它的工作机制和ZooKeeper非常相似,一般也是由奇数个节点组成,同样遵循Paxos协议,同样满足过半成功机制,即只要一半以上的节点写成功,就认为成功。除QJM外,还有其他的共享存储方式,如NFS,但是因为NFS对硬件有要求,且部署麻烦,所以现在使用QJM较多。

分析可以发现,namenode的元数据信息共享问题的主要难点就在于edits文件的共享问题,因此namenode不再仅仅是把edits文件保存在本地中,还要写到上文介绍的QJM中。每个JournalNode对外有一个简易的RPC接口,以供namenode读写edits文件到QJM。当写edits数据时,namenode会同时向所有JournalNode并行写文件,只要有N/2+1结点写成功则认为此次写操作成功,遵循Paxos协议。为了提高写edits文件的效率,namenode启动了两个不同的输出流:EditLogFileOutputStream(本地输出流)和QuorumOutputStream(JN输出流)。同时为了减少IO消耗、提高写效率,namenode会分别为EditLogFileOutputStream和QuorumOutputStream定义两个同等大小的Buffer,大小约为512KB,一个为写Buffer(buffCurrent),一个为同步Buffer(buffReady),这样可以一边写一边同步,这在大数据组件中是一种非常常见的处理方法,所以edits是一个异步写过程,同时也是一个批量同步的过程,避免每写一笔就同步一次日志。

Hadoop笔记(5)HA和联邦机制
图2 edits同步buffer

既然edits是异步写的,怎么保证缓存中的数据不丢呢?其实这里虽然是异步,但实际所有日志都需要通过logSync同步成功后才会给client返回成功码,假设某一时刻NameNode不可用了,其内存中的数据其实是未同步成功的,所以client会认为这部分数据未写成功。这样,active namenode往QJM上写edits数据,其他standby namenode从QJM同步edits数据到自己节点上就可以了。

根据上面介绍的过程,我们似乎已经有了一套完整的Hdfs HA解决方案,但是这里有一个非常重要的细节问题我们还没有解决,如果active因为网络等原因导致向zookeeper发送的心跳超时,从而导致zookeeper以为active已经挂掉,重新选举了新的active节点,而前一个active还在工作,这就会造成“脑裂”现象,相当于一个集群有了两个管理员,势必会造成冲突,所以我们还需要解决“脑裂”的风险问题。事实上,一个standby节点被选举为新的active后,并不会立即开始行使active的权利,它首先会通过ssh kill掉前一个active的相关进程,确保之前的active真的不能工作,所以一般在Hadoop集群中一般都会配置节点间的免密登录。如果ssh过程失败,或者kill失败,Hadoop还提供了一个“B计划”:允许用户配置一个shell脚本,一旦前面的ssh过程失败,就会调用这个脚本执行用户操作。

我们虽然有了“B计划”,但是也不能保证一定是有效的,所以Hadoop还提供了终极大招——“C计划”。Hadoop在切换active节点时,内部维护了一个EpochNumber变量,EpochNumber在分布式系统中是一个比较常见的机制,在ZooKeeper篇中我们介绍ZooKeeper选举leader的时候zxid也是用到了EpochNumber。当某个standby被选为新的active后,EpochNumber会加1,并分配给新的active,每个EpochNumber都是全局惟一的,不会有相同的EpochNumber出现,并且新的总是比前面的大。active发送给QJM的请求都必须携带EpochNumber,QJM节点收到请求后,会与自己保存的EpochNumber比较,如果小于自己保存的EpochNumber,则拒绝请求,如果大于自己保存的EpochNumber,则更新自己保存的EpochNumber为新的EpochNumber。QJM在收到新的EpochNumber后,会立即把EpochNumber发送给所有JN节点,JN收到后会把EpochNumber保存到一个lastPromisedEpoch变量中并持久化到本地磁盘,其实每次比较就是和lastPromisedEpoch比较。这样,即使前一个active还活着,也不会发生脑裂现象。

在单节点namenode的情况下,我们介绍了为了提高效率,由secondary namenode不断地合并edits文件到fsimage中并推送给namenode不断更新元数据信息,这个过程也称为checkpoint,在HA情况下,不再需要secondary namenode,checkpoint是由standby节点完成的,standby从QJM上获取edits数据后,与本地的fsimage文件合并生成新的fsimage文件,然后推送给active,就完成了checkpoint过程。如果active挂掉了,虽然集群还能继续工作,但是也要及时修复挂掉的namenode,因为此时没有节点执行checkpoint过程了,所以namenode修复以后加入集群成为standby需要对历史edits文件进行checkpoint,可能会花费较多的时间。

1.2 Yarn HA

相对于Hdfs的HA实现,Yarn HA的实现无疑要简单许多,同样借助了ZooKeeper实现。Yarn的HA主要是为了解决RecourseManager的单点故障问题,在RecourseManager中有一个ZKFC线程,可以发现在Hdfs的HA机制中namenode上有一个独立的ZKFC守护进程,在Yarn中ZKFC是一个在RecourseManager内部的线程。Yarn启动的时候RecourseManager节点会向zk的/rmstore中写lock文件, 写成功为active, 否则为standby。standby ResourceManager的ZKFC会一直监控lock文件是否存在,如果不存在就说明active已经挂掉,需要重新选举active,整个过程和Hdfs的active选举基本一致。

Hadoop笔记(5)HA和联邦机制
图3 Yarn HA架构

Yarn的主要功能就是负责资源分配和任务调度,因此,在HA状态下,每个RecourseManager需要共享任务状态信息。为此,active RecourseManager会向ZooKeeper的/rmstore目录下的RMStateStore写APP信息,一旦active RecourseManager挂了,另外一个standby RecourseManager通过ZKFC选举成为active,会从RMStateStore读取相应的作业信息,重新构建作业的内存信息,启动内部的服务,开始接收NodeManager的心跳,构建集群的资源信息,并且接收客户端的作业提交请求,启动和监控ApplicationMaster。还有一点需要注意的是,和Hdfs不同,Yarn的NodeManager只向active RecourseManager报告资源信息,并不是所有的RecourseManager,client、ApplicationMaster和NodeManager都会以轮询的方式尝试连接到真正的active RM,也就是说一旦active挂掉了,NodeManager就会开始去尝试找其他的standby RecourseManager连接,直到找到新的active。

在Yarn的HA机制中同样存在脑裂的风险,为了解决这个问题,RecourseManager在ZooKeeper上创建锁节点时必须携带自己的ACL信息,如果因为网络等原因导致 active “假死”,等“假死”的active复活以后,会发现当前锁节点不是自己创建的锁节点,将自动转化为standby状态。

2. Hadoop联邦机制

前面我们介绍了Hadoop的HA结构,解决了单点故障问题,但是namenode本质上还是只有一个工作节点,如果数据量很大的情况下虽然可以增加datanode提高存储能力,但是namenode可能会成为系统瓶颈,也就是元数据信息无法存储了,为了解决这个问题,Hadoop又引入了联邦机制,联邦机制多在大型企业中才会应用(数据量大)。联邦机制的原理也比较容易理解,既然一个namenode资源不足了,那就加机器,使用多个namenode,但是Hadoop多namenode的设计结构比较特殊。

Hadoop笔记(5)HA和联邦机制
图4 Hadoop联邦机制架构

如图4,Hadoop的联邦机制采用了横向扩展的方式,但并不是每个namenode负责独立的部分datanode节点,因为这相当于是多个集群。Hadoop将datanode节点的资源分为多份,每一份由一个namenode负责维护元数据信息,每个namenode之间是独立的,彼此之间不需要协调,datanode向所有的namenode报告心跳信息和block信息,同时处理来自namenode的命令,datanode通过NameServiceId区分不同的namenode。一个namenode故障不会影响集群中的其他namenode提供服务。联邦机制的好处是显而易见的,不仅增加了系统的水平扩展性,而且突破了单namenode节点的吞吐瓶颈,另外多namenode还提供了一种天然的数据隔离机制,单个namenode在多用户环境中不提供读隔离。

联邦机制虽然带来了很多便利,但是也附带了一些新的问题,最典型的就是由于namespace被拆分成多个,且互相独立,一个文件路径只允许存在一个namespace中,如果应用程序需要访问多个文件路径(跨namespace),那么不可避免的会产生交叉访问namespace的情况,比如MR、Spark任务,都会存在此类问题。此外,启用Federation后,HDFS很多管理命令都会失效,比如hdfs dfsadmin、hdfs fsck、hdfs dfs cp/mv等,如果要在不同Namespace间拷贝或移动数据,需要使用distcp命令,指定绝对路径。HDFS路径Scheme需要变为ViewFs,ViewFs路径和其他Scheme路径互不兼容,比如DistributedFileSystem无法处理ViewFs为Scheme的路径,也就是说如果启用Federation,则需要将历史作业中的所有HDFS路径的scheme改为viewfs,会产生改造成本。

Scheme是URI命名结构([scheme:][//authority][path][?query][#fragment])中的一部分,用于标识URI所使用的协议,HDFS路径也是一个URI,常见的Scheme为hdfs,在Federation方案中,HDFS路径Scheme为ViewFs,指在HDFS客户端上下文中,将ViewFs为Scheme的一个路径,比如viewfs://ns/user,映射到一个具体的HDFS路径上,比如hdfs://ns2/user,这个路径可以是任意Scheme的HDFS路径,这样对于viewfs://ns/user实际上会被转换为对hdfs://ns2/user的操作。

3. Hadoop3新功能

Hadoop3.x版本是Hadoop版本中一个重要的大版本更新,也做了许多更新:

  1. 最低支持jdk1.8,不再支持jdk1.7。
  2. Hadoop3.x使用擦除编码来提供容错能力,相对于Hadoop2中的replication容错机制,可以节约存储资源。但是,在CPU和网络方面始终存在编码和解码过程的开销。因此,它用于很少访问的数据。
  3. Yarn时间轴服务。时间轴服务器是Hadoop3中的新增功能,负责存储和检索应用程序的当前和历史信息。
  4. 支持机会容器和分布式计划。Hadoop3引入了执行类型的概念,如果目前没有可用资源,则这些容器将在NodeManager中等待。机会容器的优先级低于保证容器。如果有保证容器到达机会容器执行的中间,则随后将被抢占。这恰好为保证容器腾出了空间。
  5. 更改多个服务的默认端口。在Hadoop3.0之前,许多Hadoop服务的默认端口在Linux临时端口范围(32768一61000)中。因此,很多时候这些服务在启动时将无法绑定,因为它们会与其他应用程序冲突。.他们已将这些服务的默认端口移出了临时范围。服务包括NameNode, Secondary NameNode,DataNode和KeyManagementServer。
  6. Intra一DataNode平衡器。DataNode管理许多磁盘。在写操作期间,这些磁盘被均匀填充。但是,当我们添加或删除磁盘时,会导致严重的偏差,平衡器解决了这种情况。CLI 一 hdfs diskbalancer调用此平衡器。
  7. 支持多个NameNode。
  8. 重构后台程序和任务对管理。
  9. 支持随机Container。
  10. 重写Shell脚本。Hadoop的shell脚本被重写,修补了许多长期存在的bug,并增加了一些新的特性。

......

参考资料

[1] https://www.cnblogs.com/qcloud1001/p/7693476.html

[2] https://blog.csdn.net/xwd127429/article/details/105931784

上一篇:Hadoop和yarn面试题(详解)


下一篇:Initial job has not accepted any resources; check your cluster UI to ensure that workers are regist