Hadoop 源码学习笔记(7)--Yarn 与 Hdfs 的源码系统设计差异

看过了 Hdfs 和 Yarn 的源码,发现两者的系统设计完全不同,根本不像是同一个 Project 的 Module,觉得很有必要对这两个 Module 源码的系统设计做一次分析。

我私下里认为两者源码系统设计之所以不同的原因无非是:

  1. Hdfs Module 出现的时间较早,整个 Module 的系统设计也是在开源之初就已经确定完成,之后的版本迭代中,都是基于原版 Hdfs 的代码逐步演进的,因此他的整个系统设计比较粗糙,偏实用型,结构大而全。
  2. 在 Yarn 之前, Hadoop 还有一个 ResourceManager 组件,叫做 JobTracker, Yarn 是后续开发人员重新设计的 ResourceManager,因此 Yarn 在设计之初,整个 Project 已经处于社区维护阶段,更由于全新建设的原因,扔掉了 JobTracker 的历史包袱,他的系统设计相对比较良好,拥有服务化和消息总线两把神兵利器。

言归正传,我们回到 Yarn 和 Hdfs 的系统设计本身,虽然 Yarn 和 Hdfs 两个 Module 各自有自身不同的多种节点,但是同一个 Module 中的节点的系统设计大致一致。在这里我只针对 Yarn 中的 ResourceManager 和 Hdfs 中的 NameNode 两者进行系统设计分析,其余节点可以参考着对应 Module 进行查看,不再做一一分析。

NameNode 的系统设计

系统结构

NameNode 作为 Hdfs 的文件系统管理节点,他的整体系统设计可以用下图进行表示

《Hadoop 源码学习笔记(7)--Yarn 与 Hdfs 的源码系统设计差异》 NameNode

整个 NameNode 可以总结为上图。

最上方是两个对外暴露服务,一个是 HttpServer 负责提供 Http 服务展示当前的节点状态,一个是 RPCServer 负责集群间的内部通信。

第二层是一个中介者,负责响应 HttpServer 和 RpcServer 的请求,一般而言所有的请求操作都会通过 FSNamesystem 再向下分发。

第三层是具体的业务模块,主要由 BlockManager 和 FSDirectory,MetricsSystem 构成。其中 BlockManager 负责维护 DataNode 的相关信息,并持有 DataNode 所拥有的 Block 列表;FSDirectory 则负责维护当前 NameNode 的文件系统;MetricsSystem 负责记录一些行为操作细节,例如 gc 时间,节点数量等。

最下方是几个底层模块,上图中我也只列举出了部分常用的 Manager,业务模块通过对底层模块的调用实现其业务逻辑。

启动逻辑

之前的章节 中有简单提过 Hdfs 的启动流程。

protected void initialize(Configuration conf) throws IOException {
    // 启动 MetricsSystem
    NameNode.initMetrics(conf, this.getRole());
    
    if (NamenodeRole.NAMENODE == role) {
        // 启动 HttpServer
        startHttpServer(conf);
    }
    
    // 启动 FSNamesystem
    loadNamesystem(conf);
    
    // 启动 RpcServer
    rpcServer = createRpcServer(conf);
}

在入口函数 NameNode::main 中,我们看到对于各个模块的加载是完全放在 NameNode::initialize 中进行的。

这样的做法自然是足够简单,但和 Yarn 的设计比起来就显得略微粗糙了。

Yarn 的系统设计

本文的主要介绍会在 Yarn 上,作为 Hadoop 2.x 才推出的 ResourceManager,它的系统设计相较于 Hadoop 有了很大的提升。

系统结构

《Hadoop 源码学习笔记(7)--Yarn 与 Hdfs 的源码系统设计差异》 ResourceManager

上图中列出了 ResourceManager 中的一些关键组件,这些组件都继承了 Service 接口,也就是说在 ResourceManager 中的各个组件都已经 Service 化了。

ResourceManager 中默认实现了 HA 逻辑,当同时存在多个 ResourceManager 时,会通过内置的 EmbeddedElector 进行主从选举。默认的 EmbeddedElector 是 ActiveStandbyElectorBasedElectorService,在默认实现类中,同 zkfc 共享同一个主从选举逻辑,具体选举逻辑在上一篇文章中有对应介绍: Hadoop 源码学习笔记(6)–Hdfs 的备份,高可用和横向扩展。选举结束之后,只有 ActiveResourceManager 才能够启动 RMActiveServices。

而 RMActiveServices 是多个 Service 组件组成的一个集合 Service,这些 Service 负责维护当前集群中的 NodeManager 和正在运行的 App 信息。只有启动了 RMActiveServices 的 ResourceManager 才能够接收 Client 提交的 App 信息,并通过 ApplicationMasterLauncher 在 NodeManager 中开启对应的 ApplicationMaster,进入任务处理流程。

Service 化

《Hadoop 源码学习笔记(7)--Yarn 与 Hdfs 的源码系统设计差异》 Service

Service 是 Yarn 中抽象出的一种组件生命周期,由 init、start、stop 三个接口方法,如方法名所示,分别对应服务的初始化、启动和终止三种行为。

在 Yarn 中,系统将每一个组件抽象化成一个 Service,若涉及到多个 Service 聚合使用,则会通过 addService 和 addIfService 方法将多个 Service 聚合到同一个 Service 中,并共享上级 Service 的生命周期。

通过生命周期共享这一策略,可以确保由 ResourceManager 启动的所有 Service 共同享有一套生命周期,上层的 Service 通过分发消息给下层的 Service,确保所有 Service 按需启动和退出。

消息总线

在 Hdfs 中,事件的分发是直接通过对对象的调用进行直接操作的,因此追踪相对简单,方便源码走读。

但是在 Yarn 中,所有事件分发都是通过消息总线完成的。在 ResourceManager 或者 NodeManager 中均会启动一个 AsyncDispatcher 对象,负责接收并分发事件。

《Hadoop 源码学习笔记(7)--Yarn 与 Hdfs 的源码系统设计差异》 AsyncDispatcher

Service 通过向 AsyncDispatcher 中 register EventHandler,可以将 EventType 和 EventHandelr 一一对应的注册进入 AsyncDispatcher 中。当使用 dispatch 进行事件分发时,根据对应的 Event,选取对应 EventHandler 进行事件消费。

通过消息总线机制,只要获取到了 AsyncDispatcher 对象,就可以对任意事件进行监听操作。这对服务管理来说是比较方便的,我们可以保证所有事件分发均运行在同一线程,并且可以在任意位置进行事件注册,但是当我们进行源码走读的时候,由于事件可能在任务位置被注册,故会对走读造成一定影响。

总结

组件模块逻辑消息事件分发
Hdfs全部在 main 方法中依次注册,需要自身维护生命周期通过组件间的相互调用实现消息分发
Yarn子模块被抽象成 Service,和顶层 Service 共享同一个生命周期通过消息总线进行事件分发
    原文作者:kifile
    原文地址: https://www.jianshu.com/p/afe2826ddbf8
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞