Genluo / Precipitation-and-Summary

梳理体系化的知识点&沉淀日常开发和学习
MIT License
16 stars 1 forks source link

《大数据技术》(七)Hadoop再讨论 #88

Open Genluo opened 4 years ago

Genluo commented 4 years ago

Hadoop的优化和发展

1、Hadoop的局限与不足

Hadoop中核心组件(Mapreduce和HDFS)主要存在下面不足的地方:

  1. 抽象层次低:需要手工编写代码来完成,有时只是为了实现一个简单的功能,也需要编写 大量的代码。
  2. 表达能力有限:MapReduce 把复杂分布式编程工作高度抽象到两个函数上,即 Map 和 Reduce,在降低开发人员程序开发复杂度的同时,却也带来了表达能力有限的问题,实际生产环境中的一些应用是无法用简单的 Map 和 Reduce 来完成的。
  3. 开发者自己管理作业之间的依赖关系:一个作业(Job)只包含 Map 和 Reduce 两个阶段, 通常的实际应用问题需要大量的作业进行协作才能顺利解决,这些作业之间往往存在复杂的依赖 关系,但是 MapReduce 框架本身并没有提供相关的机制对这些依赖关系进行有效管理,只能由开 发者自己管理。
  4. 难以看到程序整体逻辑:用户的处理逻辑都隐藏在代码细节中,没有更高层次的抽象机制对程序整体逻辑进行设计,这就给代码理解和后期维护带来了障碍。
  5. 执行迭代操作效率低:对于一些大型的机器学习、数据挖掘任务,往往需要多轮迭代才能得到结果。采用 MapReduce 实现这些算法时,每次迭代都是一次执行 Map、Reduce 任务的过程, 这个过程的数据来自分布式文件系统 HDFS,本次迭代的处理结果也被存放到 HDFS 中,继续用 于下一次迭代过程。反复读写 HDFS 文件中的数据,大大降低了迭代操作的效率。
  6. 资源浪费:在 MapReduce 框架设计中,Reduce 任务需要等待所有 Map 任务都完成后才可 以开始,造成了不必要的资源浪费。
  7. 实时性差:只适用于离线批数据处理,无法支持交互式数据处理、实时数据处理。

2、针对Hadoop的改进与提升

image-20190624194011305

image-20190624194030053

HDFS新特性

1、HDFS HA

对于分布式系统,名称节点是系统的核心,存储各类元数据,并负责管理文件系统的命名空间和客户端对文件的访问,但是这样存在说的单点故障问题,虽然 HDFS1.0 中存在一个“第二名称节点(Secondary NameNode)”,但是第二名称节点并不是名称节点的备用节点,它与名称节点有着不同的职责,其主要功能是周期性地从名称节点获取命名空间镜像文件(FsImage)和修改日志(EditLog),进行合并后再发送给名称节点,替换掉原来的 FsImage,以防止日志文件 EditLog 过大,导致名称节点失败恢复时消耗过多时间。合并后的命名空间镜像文件 FsImage 在第二名称节点中也保存一份,当名称节点失效的时候,可以使用第二名称节点中的 FsImage 进行恢复。

但是第二节点无法提供热备份功能,即在名称节点发生故障的时候,系统无法实时切换到第二名称节点立即对外提供服务,仍然需要进行停机恢复,因此 HDFS1.0 的设计是存在单点故障问题的。

为了解决这个单点故障问题,一般设置两个名称节点,其中一个名称节点处于“活跃(Active)”状态,另一个处于 “待命(Standby)”状态 处于活跃状态的名称节点负责对外处理所有客户端的请求,而处于待命状态的名称节点则作为备用节点,保存了足够多的系统元数据,当名称节点出现故障时提供快速恢复能力。也就是说,在 HDFS HA 中,处于待命状态的名称节点提供了“热备份”,一旦活跃名称节点出现故障,就可以立即切换到待命名称节点,不会影响到系统的正常对外服务。

image-20190624195701859

由于待命名称节点是活跃名称节点的“热备份”,因此活跃名称节点的状态信息必须实时同步 到待命名称节点。两种名称节点的状态同步,可以借助于一个共享存储系统来实现,比如 NFS (Network File System)、QJM(Quorum Journal Manager)或者 Zookeeper。活跃名称节点将更新数 据写入到共享存储系统,待命名称节点会一直监听该系统,一旦发现有新的写入,就立即从公共存储系统中读取这些数据并加载到自己的内存中,从而保证与活跃名称节点状态完全同步

此外,名称节点中保存了数据块(Block)到实际存储位置的映射信息,即每个数据块是由哪个数据节点存储的。当一个数据节点加入 HDFS 集群时,它会把自己所包含的数据块列表报告给名称节点,此后会通过“心跳”的方式定期执行这种告知操作,以确保名称节点的块映射是最新的。因此,为了实现故障时的快速切换,必须保证待命名称节点一直包含最新的集群中各个块的位置信息。为了做到这一点,需要给数据节点配置两个名称节点的地址(即活跃名称节点和待命名称节点),并把块的位置信息和心跳信息同时发送到这两个名称节点。为了防止出现“两个管家” 现象,HA 还要保证任何时刻都只有一个名称节点处于活跃状态,否则,如果有两个名称节点处于活跃状态 HDFS 集群中出现“两个管家”,就会导致数据丢失或者其他异常,这个任务是由Zookeeper 来实现的,Zookeeper 可以确保任意时刻只有一个名称节点提供对外服务。

2、HDFS联邦

HDFS1.0中存在的问题:

HDFS1.0 采用单名称节点的设计,不仅会带来单点故障问题,还存在可扩展性、性能和隔离 性等问题。在可扩展性方面,名称节点把整个 HDFS 文件系统中的元数据信息都保存在自己的内 存中,HDFS1.0 中只有一个名称节点,不可以水平扩展,而单个名称节点的内存空间是有上限的, 这限制了系统中数据块、文件和目录的数目。是否可以通过纵向扩展的方式(即为单个名称节点 增加更多的 CPU、内存等资源)解决这个问题呢?答案是否定的。纵向扩展带来的第一个问题就 是,会带来过长的系统启动时间,比如一个具有 50 GB 内存的 HDFS 启动一次大概需要消耗 30min~2h,单纯增大内存空间只会让系统启动时间变得更长。其次,当在内存空间清理时发生 错误,就会导致整个 HDFS 集群宕机。

在系统整体性能方面,整个 HDFS 文件系统的性能会受限于单个名称节点的吞吐量。在隔离性方面,单个名称节点难以提供不同程序之间的隔离性,一个程序可能会影响其他运行的程序(比如一个程序消耗过多资源导致其他程序无法顺利运行)。HDFS HA 虽然提供了两个名称节点,但是在某个时刻也只会有一个名称节点处于活跃状态,另一个则处于待命状态。因而,HDFS HA在本质上还是单名称节点,只是通过“热备份”设计方式解决了单点故障问题,并没有解决可扩展性、系统性能和隔离性三个方面的问题。

HDFS联邦的设计:

HDFS 联邦可以很好地解决上述三个方面的问题。在 HDFS 联邦中,设计了多个相互独立的名称节点,使得 HDFS 的命名服务能够水平扩展, 名称节点分别进行各自命名空间和块的管理,相互之间都是联邦关系,不需要彼此协调,HDFS联邦并不是真正的分布式设计,但是 采用这种简单的“联合”设计方式,在实现和管理复杂性方面,都要远低于真正的分布式设计,而且可以快速满足需求。在兼容性方面,HDFS 联邦具有良好的向后兼容性,可以无缝的支持单名称节点架构中的配置,所以,原有针对单名称节点的部署配置,不需要作任何修改就可以继续工作。

HDFS 联邦中的名称节点提供了命名空间和块管理功能。在 HDFS 联邦中,所有名称节点会共享底层的数据节点存储资源, 。每个数据节点要向集群中所有的名称节点注册,并周期性地向名称节点发送“心跳”和块信息,报告自己的状态,同时也会处理来自名称节点的指令。

HDFS1.0 只有一个命名空间,这个命名空间使用底层数据节点全部的块。与 HDFS1.0 不同的是,HDFS 联邦拥有多个独立的命名空间,其中,每一个命名空间管理属于自己的一组块,这些属于同一个命名空间的块构成一个“块池”(Block Pool)。每个数据节点会为多个块池提供块的存储。可以看出,数据节点是一个物理概念,而块池则属于逻辑概念,一个块池是一组块的逻辑集合,块池中的各个块实际上是存储在各个不同的数据节点中的。因此,HDFS 联邦中的一个名称节点失效,也不会影响到与它相关的数据节点继续为其他名称节点提供服务。

HDFS联邦访问方式

对于 HDFS 联邦中的多个命名空间,可以采用客户端挂载表(Client Side Mount Table)方式 进行数据共享和访问。每个阴影三角形代表一个独立的命名空间,上方空白三角形表示从客户方 向去访问下面子命名空间,如图 8-3 所示。客户可以访问不同的挂载点来访问不同的子命名空间。 这就是 HDFS 联邦中命名空间管理的基本原理,即把各个命名空间挂载到全局“挂载表” (Mount-table)中,实现数据全局共享;同样地,命名空间挂载到个人的挂载表中,就成为应用程 序可见的命名空间

image-20190624201838926

资源管理调度框架YARN

设计思路

体系结构

工作流程

MapReduce1.0 采用 Master/Slave 架构设计(见图 8-4),包括一个 JobTracker 和若干个TaskTracker,前者负责作业的调度和资源的管理,后者负责执行 JobTracker 指派的具体任务。这种架构设计具有一些很难克服的缺陷,具体如下。

(1) 存在单点故障。由 JobTracker 负责所有 MapReduce 作业的调度,而系统中只有一个 JobTracker, 因此会存在单点故障问题,即这个唯一的 JobTracker 出现故障就会导致系统不可用。

(2) JobTracker“大包大揽”导致任务过重。JobTracker 既要负责作业的调度和失败恢复,又 要负责资源管理分配。执行过多的任务,需要消耗大量的资源,例如,当存在非常多的 MapReduce 任务时,JobTracker 需要巨大的内存开销,这也潜在地增加了 JobTracker 失败的风险。正因如此, 业内普遍总结出 MapReduce1.0 支持主机数目的上限为 4 000 个。

(3) 容易出现内存溢出。在 TaskTracker 端,资源的分配并不考虑 CPU、内存的实际使用情 况,而只是根据MapReduce 任务的个数来分配资源,当两个具有较大内存消耗的任务被分配到同 一个 TaskTracker 上时,很容易发生内存溢出的情况。

(4) 资源划分不合理。资源(CPU、内存)被强制等量划分成多个“槽”(Slot),槽又被进 一步划分为 Map 槽和 Reduce 槽两种,分别供 Map 任务和 Reduce 任务使用,彼此之间不能使用 分配给对方的槽,也就是说,当 Map 任务已经用完 Map 槽时,即使系统中还有大量剩余的 Reduce 槽,也不能拿来运行 Map 任务,反之亦然。这就意味着,当系统中只存在单一 Map 任务或 Reduce 任务时,会造成资源的浪费。

image-20190624202522385

1、设计思路

基本思路就是“放权”,即不让 JobTracker 这一个组件承担过多的功能,把原 JobTracker 三大功能(资源管理、任务调度和任务监控)进行拆分,分别交给不同的新组件去处理。重新设计后得到的 YARN 包括 ResourceManager、ApplicationMaster 和NodeManager,其中,由 ResourceManager 负责资源管理,由 ApplicationMaster 负责任务调度和监控,由 NodeManager 负责执行原 TaskTracker 的任务。通过这种“放权”的设计,大大降低了JobTracker 的负担,提升了系统运行的效率和稳定性。

image-20190624202845146

2、体系结构

YARN 体系结构中包含了三个组件:ResourceManagerApplicationMasterNodeManager

image-20190624211256411

image-20190624211334423

ResourceManager(RM)是一个全局的资源管理器,负责整个系统的资源管理和分配,主要包括两个组件,即调度器(Scheduler)和应用程序管理器(Applications Manager)。调度器主要负责资源管理和分配,不再负责跟踪和监控应用程序的执行状态,也不负责执行失败恢复,因为这些任务都已经交给 ApplicationMaster 组件来负责。调度器接收来自 ApplicationMaster 的应用程序资源请求,并根据容量、队列等限制条件(如每个队列分配一定的资源,最多执行一定数量的作业等),把集群中的资源以“容器”的形式分配给提出申请的应用程序,容器的选择通常会考虑应用程序所要处理的数据的位置,进行就近选择,从而实现“计算向数据靠拢”。在 MapReduce1.0中,资源分配的单位是“槽”,而在 YARN 中是以容器(Container)作为动态资源分配单位,每个容器中都封装了一定数量的 CPU、内存、磁盘等资源,从而限定每个应用程序可以使用的资源量。同时,在 YARN 中调度器被设计成是一个可插拔的组件,YARN 不仅自身提供了许多种直接可用的调度器,也允许用户根据自己的需求重新设计调度器。应用程序管理器负责系统中所有应用程序的管理工作,主要包括应用程序提交、与调度器协商资源以启动ApplicationMaster、监控ApplicationMaster 运行状态并在失败时重新启动等。

在 Hadoop 平台上,用户的应用程序是以作业(Job)的形式提交的,然后一个作业会被分解成多个任务(包括 Map 任务和 Reduce 任务)进行分布式执行。ResourceManager 接收用户提交的作业,按照作业的上下文信息以及从 NodeManager 收集来的容器状态信息,启动调度过程,为用户作业启动一个 ApplicationMaster。ApplicationMaster 的主要功能是:

  1. 当用户作业提交时,ApplicationMaster 与 ResourceManager 协商获取资源,ResourceManager 会以容器的形式为ApplicationMaster 分配资源;
  2. 把获得的资源进一步分配给内部的各个任务(Map 任务或 Reduce任务),实现资源的“二次分配”
  3. 与 NodeManager 保持交互通信进行应用程序的启动、运行、监控和停止,监控申请到的资源的使用情况,对所有任务的执行进度和状态进行监控,并在任务发生失败时执行失败恢复(即重新申请资源重启任务)
  4. 定时向 ResourceManager 发送“心跳”消息,报告资源的使用情况和应用的进度信息
  5. 当作业完成时,ApplicationMaster 向ResourceManager 注销容器,执行周期完成。

NodeManager 是驻留在一个 YARN 集群中的每个节点上的代理,主要负责容器生命周期管理,监控每个容器的资源(CPU、内存等)使用情况,跟踪节点健康状况,并以“心跳”的方式与ResourceManager 保持通信,向 ResourceManager 汇报作业的资源使用情况和每个容器的运行状态,同时,它还要接收来自 ApplicationMaster 的启动/停止容器的各种请求。需要说明的是,NodeManager 主要负责管理抽象的容器,只处理与容器相关的事情,而不具体负责每个任务(Map任务或 Reduce 任务)自身状态的管理,因为这些管理工作是由ApplicationMaster 完成的,ApplicationMaster 会通过不断与 NodeManager 通信来掌握各个任务的执行状态

在集群部署方面,YARN 的各个组件是和 Hadoop 集群中的其他组件进行统一部署的。如图8-7 所示,YARN 的 ResourceManager 组件和 HDFS 的名称节点(NameNode)部署在一个节点上,YARN 的 ApplicationMaster 及 NodeManager 是和 HDFS 的数据节点(DataNode)部署在一起的。YARN 中的容器代表了 CPU、内存、网络等计算资源,它也是和 HDFS 的数据节点一起的。

image-20190624212452615

3、工作流程

YARN 的工作流程如图 8-8 所示,在 YARN 框架中执行一个 MapReduce 程序时,从提交到完成需要经历如下 8 个步骤。

  1. 用户编写客户端应用程序,向 YARN 提交应用程序,提交的内容包括 ApplicationMaster 程序、启动 ApplicationMaster 的命令、用户程序等
  2. YARN 中的 ResourceManager 负责接收和处理来自客户端的请求。接到客户端应用程序请 求后,ResourceManager 里面的调度器会为应用程序分配一个容器。同时,ResourceManager 的应 用程序管理器会与该容器所在的 NodeManager 通信,为该应用程序在该容器中启动一个 ApplicationMaster(即图 8-8 中的“MR App Mstr”)
  3. ApplicationMaster 被创建后会首先向 ResourceManager 注册,从而使得用户可以通过 ResourceManager 来直接查看应用程序的运行状态。接下来的步骤 4~7 是具体的应用程序执行 步骤
  4. ApplicationMaster 采用轮询的方式通过 RPC 协议向 ResourceManager 申请资源。
  5. ResourceManager 以“容器”的形式向提出申请的 ApplicationMaster 分配资源,一旦 ApplicationMaster 申请到资源后,就会与该容器所在的 NodeManager 进行通信,要求它启动 任务。
  6. 当 ApplicationMaster 要求容器启动任务时,它会为任务设置好运行环境(包括环境变量、 JAR 包、二进制程序等),然后将任务启动命令写到一个脚本中,最后通过在容器中运行该脚本 来启动任务。
  7. 各个任务通过某个 RPC 协议向 ApplicationMaster 汇报自己的状态和进度,让 ApplicationMaster 可以随时掌握各个任务的运行状态,从而可以在任务失败时重新启动任务。
  8. 应用程序运行完成后,ApplicationMaster 向 ResourceManager 的应用程序管理器注销并关闭自己。若 ApplicationMaster 因故失败,ResourceManager 中的应用程序管理器会监测到失败的情形,然后将其重新启动,直到所有的任务执行完毕。

image-20190624213422457

YARN中的优点: