一直想对Hadoop有一个比较全面的了解,这次正好趁做作业的机会,对第一代和第二代Hadoop架构进行了整理和分析。文中第二代Hadoop的内容主要来自第一篇参考文献——发表在SoCC2013上的一篇文章。(文中的图片都来自于文后所列出的参考文献。)
Hadoop是一个开源的分布式系统框架,由Apache基金会开发,是当前最热门的大数据技术。它一开始主要应用在一些大型网站,如Yahoo!、Facebook、淘宝、百度等。随着人们对大数据的价值越来越重视,Hadoop开始在各类企业中得到广泛应用,成为人们对大数据进行存储、分析和挖掘的最主要的工具。Hadoop的应用已经形成了一个强大稳定的生态系统。
Hadoop的出现受到Google两篇论文(The Google File System和MapReduce: SimplifiedData Processing on Large Clusters)的启发。其设计初衷是解决搜索引擎中的可扩展性问题。Hadoop最大的特点是可以将数千台普通的廉价商用服务器组成一个稳定可靠、计算能力强大的集群,能够对PB量级的数据进行存储和计算。
Hadoop可以使用户可以在不了解底层细节的情况下,开发分布式的应用程序,实现高效可靠的分布式计算。Hadoop基于java开发,用户可以用java, C/C++开发自己的应用。
Hadoop技术以其低廉的成本和强大的计算能力得到人们的广泛认可。人们对Hadoop技术的使用已经远远超出了Hadoop最初的设计目标,同时也暴露出越来越多的问题。人们对Hadoop的可扩展性、可靠性、可用性都提出了更高的要求。2013年末,第二代Hadoop系统YARN发布。新的架构在原来的基础上作了很多改进,性能和可扩展性更高,而且可以支持更多的计算模型。
本文第二部分介绍第一代Hadoop技术的架构,并分析其优缺点;第三部分介绍第二代Hadoop技术YARN的架构;第四部分简单介绍跟Hadoop类似的计算框架;第五部分对本文进行总结。
第一代Hadoop从资源管理到任务调度都采用了主从结构。如图1所示,Hadoop有两个核心组件:HDFS和MapReduce编程框架。下面分别对这两个组件进行介绍。
图 1 第一代Hadoop 生态系统
HDFS是Hadoop Distributed File System的简称。它是一个高度容错的分布式文件系统,可以部署在廉价集群上,实现高吞吐量的数据访问。在HDFS中,大的数据集被分成很多小块,每一块有多个备份并保存在不同的节点上,从而实现大规模数据的分布式可靠存储。另外,在计算时,数据并不需要大量移动,而是由调度器将执行程序加载到存储数据的节点上,通过数据的本地化降低数据访问开销,节省网络带宽。这保证了在处理数据密集型任务时的高效性。
如图 2所示,HDFS采用主从结构(master-slave),由NameNode、Secondary NameNode和DataNode几个组件组成。用户 ( Client)必须通过NameNode跟DataNode交互,访问HDFS中的文件。
(1) NameNode
NameNode是整个Hadoop系统的控制节点(master),负责管理HDFS的目录树和相关文件的元数据信息。一个Hadoop集群中只有一个NameNode,用户通过它跟Hadoop集群交互,加载计算任务。NameNode还负责监控各个DataNode的健康状态。
(2) SecondaryNameNode
SecondaryNamenode并不是NameNode的备份节点,而是定期合并fsimage和edits日志,并发送给NameNode。其目的是为了减轻NameNode的压力。
图 2 第一代Hadoop中的资源管理和任务调度
(3) DataNode
每个Slave节点都是一个DataNode,它负责实际的数据存储,并将数据信息态定期汇报给NameNode。DataNode以固定大小的块为基本单位组织文件内容,块的默认大小为64MB。当用户上传一个大于64MB的文件时,该文件会被切成若干块,每一块都有多个备份(配置中默认为3),并且保存在不同的DataNode上,以实现可靠的数据存储。
如图 2所示,MapReduce 框架也是一个主从结构,主要由JobTracker和TaskTracker组成。其中,JobTracker运行在NameNode上,是MapReduce 框架的master;而每个DataNode上都有一个TaskTraker。JobTracker和各个TaskTracker通过心跳协议进行通信,监视hadoop集群的资源占用和任务运行。
(1) JobTracker
JobTracker 负责资源监控和作业调度。它监控所有TaskTracker 与作业的健康状况,一旦发现失败情况就会将相应的任务转移到其他节点。同时,JobTracker 会跟踪任务的执行进度、资源使用量等信息,并将这些信息告诉任务调度器。调度器根据资源的空闲状态,加载合适的计算任务。在Hadoop 中,任务调度器是一个可插拔的模块,用户可以根据自己的需要设计相应的调度器。
(2) TaskTracker
TaskTracker通过心跳协议周期性地将本节点上的资源占用和任务运行情况汇报给JobTracker,同时接收JobTracker 发送过来的命令并执行相应的操作(如启动新任务、杀死任务等)。TaskTracker 使用“slot”划分本节点上的资源。在MapReduce框架中,有Map slot 和Reduce slot 两种。每个任务使用的Map slot 和Reduce slot一旦分配好就不能再动态改变,而且这两种slot也不能相互替换使用。所以slot分配不合理会导致资源利用率下降。同时,slot 数目也限定了任务的并发度。
图3 MapReduce任务
一个MapReduce任务的运行如图3所示。左边为用户的输入数据,被分成多份保存在HDFS文件系统中。该任务包括3个map和1个reduce,分别在不同的DataNode上运行。右边为任务执行后得到的计算结果。
由上面对HDFS和MapReduce的介绍可以看出,第一代Hadoop系统主要是为了实现在廉价集群上运行大规模的MapReduce数据密集型计算任务。它在可扩展性和容错性上的优势,使得它在短短几年里就获得业界的广泛支持和认可。在某些大型的互联网公司中,一个Hadoop集群可以扩展到4000多台服务器。
Hadoop不仅在网页搜索中得到广泛应用,还被各种类型的企业用于大数据的存储、分析和挖掘。在很多企业中,Hadoop集群已经成为全公司多个部门共享数据和计算资源的基础设施。人们在Hadoop集群上运行的任务越来越多,任务的类型也不再局限于MapReduce编程框架。人们对Hadoop系统的广泛使用,已经超出了Hadoop系统的最初设计目标,暴露出第一代Hadoop系统的两个缺点:
(1) 资源管理跟特定编程框架MapReduce强绑定,使得用户开始抱怨MapReduce模型的局限性;
(2) 对资源管理和任务调度的集中控制,使得JobTracker成为系统的瓶颈,限制了系统的进一步扩展。
另外,资源无法动态分配,有时使得hadoop集群的利用率很低。
第一代Hadoop系统的局限性早已成为学术界和开源社区的共识。从Hadoop 0.23版本开始,一个全新的Hadoop系统就开始开发,并在2013年发布。这就是第二代Hadoop系统YARN。
第一代Hadoop系统中,资源管理和任务调度都是主从结构。这使得NameNode成为系统的单点故障节点,而JobTracker也很容易成为系统的性能瓶颈。为了克服这些缺点,第二代Hadoop系统将JobTracker中的资源管理和任务调度分离。资源管理主要由运行在NameNode上的资源管理器(RM:Resource Manager)负责;而每一个应用都有自己独立的ApplicationMaster(AM),用于向RM申请资源,并负责任务的加载和容错处理。另外,在每个工作节点上都有一个NodeManager(NM),负责监控本地的资源占用和任务运行情况,并通过心跳协议上报给RM。
另外,在YARN中,每个AM可以根据自己的运行情况和当前的资源占用状态动态地调整资源申请,从而避免了在第一代Hadoop系统中slot静态分配,且map任务无法使用reduce slot(或者相反)所带来的资源浪费问题。
图表 4 4第二代Hadoop系统
YARN的架构如图4所示。RM是一个运行在特定节点上的守护进程,负责资源的集中调度。它可以根据资源的全局视图实施基于容量、公平或者局部性的调度策略。RM根据应用程序的需求、调度的优先级和资源的空闲状态动态地为各个应用创建容器,或者叫做资源契约。一个容器是跟某个工作节点对应的资源集合的抽象描述,类似于操作系统中的进程。为了分配和监控资源,RM需要跟运行在每个工作节点上的NM守护进程进行交互。为了节省网络资源,RM和各个NM之间通过心跳协议进行通信。NM负责本地节点的资源占用监控,报告错误信息、并管理容器运行的生命周期。RM通过收集各个NM的快照信息构建集群的全局视图。
用户通过一个公共提交协议把job提交给RM。一个job要经过一系列的准入检查(如安全证书、访问权限等)才能提交给调度器,并进入就绪状态。当调度器发现有足够的资源时,就加载该job,使其进入运行态。RM中的AMService组件负责为每个AM分配一个容器,并在一个工作节点上启动它。
AM是一个job的控制中心,负责管理程序运行生命周期中的方方面面,包括动态地资源申请、程序的执行流程、错误处理和局部性优化等等。为了完成相应的job,AM需要申请并获取位于多个节点上的资源。首先,AM向RM提交资源申请(包括不同资源的比例、资源所在的位置等)。RM为AM分配资源后会创建一个契约,用于描述AM可以使用的资源。然后,AM通过一种基于令牌的安全机制向NM出示契约,并得到相应的资源。
RM对AM的语义基本不做限定,AM可以运行任意的、用任何语言编写的用户代码。AM也可以直接跟自己的容器进行通信,就象第一代Hadoop系统中JobTracker跟TaskTracker交换程序执行信息一样。
在图4中,两个Client各加载了一个job。橙色Client加载的是一个MPI应用,而粉色Client加载的是一个MapReduce应用。RM为每个job都启动了一个AM。MPI AM和它的唯一的容器都运行在左边第一个节点上;MapReduce AM运行在左起第二个节点上,它有多个容器在左边第一个节点和右边第一个节点上运行。
RM有两个外部接口,分别用于job提交和跟AM动态地进行资源访问协商。它还有一个跟NM通信的内部接口,用于集群运行状态监控和资源访问管理。RM负责处理AM的资源请求,并为AM创建容器契约和允许访问资源的令牌。另外,RM还从各个NM得到资源的空闲状态和容器的运行状态。一旦有容器运行结束,它就把信息发送给相应的AM。当有新的NM加入时(比如集群中增加了新的服务器),它也会把信息告诉各个AM。AM可以根据新的资源信息调整自己的资源申请。
RM也可以向AM申请回收资源。这一般发生在资源比较紧张的时候或者调度器为了维持既定的调度策略需要对资源进行重新调度。AM收到这种资源回收申请后,可以采取一些灵活的策略,如释放一些不重要的容器、为正在运行的任务创建检查点等。也就是说,这种处理允许应用程序采取一些保护措施,而不是简单地通过杀死应用程序的容器而抢占资源。
需要特别指出的是,RM并不负责协调应用程序的执行和容错处理。它既不提供运行程序的状态和度量信息,也不提供跟应用程序框架(如MapReduce)相关的统计信息。由于RM仅仅负责资源的调度,这使得YARN在扩展性方面比第一代Hadoop更好。
AM负责协调集群中应用程序的执行。跟应用程序中运行在工作节点上的容器一样,AM本身也是容器。RM中的AMService负责为AM分配容器,并启动相应的进程。
AM通过心跳协议周期地跟RM进行通信,发送心跳报文,并更新资源请求。AM在资源请求中描述自己的“期望”和“约束”,并通过心跳报文发送给RM。在接下来从RM返回的心跳报文中,AM得到一个容器契约,描述AM可以使用哪个节点中的资源。AM可以根据收到的信息更新自己的执行计划,以适应资源的忙闲状态。
由于RM并不解释容器的状态,它只是简单地把从NM收到的容器信息转发给AM。只有AM自己知道某个容器的退出状态是成功还是失败。
AM本身也是在工作节点上运行的容器,它本身也可能因为硬件故障而异常退出。在这种情况下,AM最好能够自己从异常退出中恢复。虽然YARN对异常退出的恢复也有一些支持,但由于RM并不了解每个AM的语义,所以这种恢复功能主要还得靠AM自己完成。
NM是在工作节点上运行的守护进程。它负责验证容器契约的真实性、管理容器运行所依赖的资源、监测容器的执行并为容器提供一系列的服务。NM向RM注册之后,则通过心跳报文报告自己的状态,并从RM接受指令。用户可以通过配置来控制NM需要向RM报告哪些信息,如内存和CPU。
YARN中的所有容器,包括AM,都由一个容器加载上下文(CLC:Container Launch Context)描述。CLC包括环境变量信息、程序执行依赖、安全令牌、NM服务载荷和创建进程的命令。一旦契约的真实性得到验证,NM就会为容器配置环境变量,将程序执行依赖的文件、执行代码拷贝到本地,然后加载相应的进程。NM也会根据从RM或者AM得到的指令杀死某个容器。
NM还要周期性地监视物理节点的状态。通过运行脚本检查硬件/软件中可能存在的问题。当NM发现有问题的时候,它就把自己的状态置成unhealth,并向RM报告。RM会根据报告下发杀死容器的指令,或者不会再将新的任务加载在该节点上。
另外,NM也可以为本地运行的容器提供一些服务,比如日志聚合并持久化。而且管理员可以通过配置添加一些可插拔的辅助服务,比如,在MapReduce程序中,使用辅助服务传递从map到reduce的中间数据。
综上所述,第二代Hadoop系统YARN通过将资源管理和任务调度分离,大大减轻了master节点的运行负载,使可扩展性得到大大提高。另外,通过动态的资源调度,使资源的利用率得到大大提升。另外,YARN不再跟某个编程框架绑定,从而可以支持更多的编程模型。它是向后兼容的,原来的MapReduce应用无须修改就可以在YARN上运行。
根据Yahoo!测试的结果,通过在一个2500节点的集群上部署YARN,使得运行效率比使用Hadoop1.x提高40%左右。这相当于增加1000个新的节点所带来的性能收益。
但是,YARN依然有它的局限性。首先,RM是一个集中控制节点,仍然存在单点故障问题,影响系统的可扩展性。而且一旦该节点出现问题,往往很难恢复正在运行的应用程序。随着人们处理的数据量越来越大,可扩展性问题仍然会再次浮出水面。另外,资源调度的灵活性也带来了调度算法的复杂性。在文献[2]中,作者发现YARN自带的调度算法有时会导致JOB饿死,或者某些计算资源得不到分配的情况。所以对于YARN,可扩展性、可靠性依然是很大的挑战。
除了YARN,人们还开发了一些其它的系统,也是旨在解决第一代Hadoop中所存在的问题。在这些系统中,跟YARN最接近的是Mesos、Omega、Corona 和Cosmos。它们分别由Twitter、Google、Facebook、Microsoft维护和使用。这些系统的目标都是要提高系统的可扩展性、改进性能和适应更多的编程模型。
Omega的设计趋向于通过分布式多级调度提高可扩展性。但是可扩展性的提高所带来的副作用是很难根据全局属性进行基于容量或者公平的调度。Corona采用一种基于推送的通信方式。Mesos跟YARN一样采用两级调度,但它是通过主动提供,而不是申请的方式分配资源。Cosmos在存储和计算配置上跟YARN的架构最相似,但它主要用于一类特定的应用程序:scope。
本文介绍了第一代和第二代Hadoop系统的架构,分析了它们的优缺点。Hadoop已经成为最热门的大数据解决方案。通过分析它的架构,我们也可以看到大数据处理对存储能力、计算能力的需求,对我们进一步了解大数据技术有很大的帮助。大数据技术才刚刚出现不久,而人类产生的数据量还在成指数增长。大数据技术还远没有达到成熟的地步,还需要更多人通过坚持不懈地努力,不断提高和优化大数据相关技术,来应对大数据带给我们的挑战。
[1] Vinod K. Vavilapalli etc. Apache Hadoop YARN:Yet Another Resource Negotiator. SoCC`13, Santa Clara, California, USA, 2013.
[2] Arka A. Bhattacharya etc. HierarchicalScheduling for Diverse Datacenter Workloads. SoCC`13, Santa Clara, California, USA, 2013.
[3] http://hadoop.apache.org/docs/r2.2.0/hadoop-yarn/hadoop-yarn-site/YARN.html
[4] http://en.wikipedia.org/wiki/Apache_Hadoop.
[5] http://www.cnblogs.com/bester/p/3255307.html
[6] http://hortonworks.com/wp-content/uploads/2013/12/Apache.Hadoop.YARN_.Sample.pdf