Hadoop 介绍

Hadoop 是目前大数据领域最主流的一个分布式计算框架,由三个核心组件组成:

  • HDFS(分布式文件系统)
    • HDFS 作为存储层,使得数据可以在多个节点上并行处理。
  • MapReduce(分布式计算系统),也可以引入 spark 等计算框架代替 MapReduce。
    • MapReduce 作为计算框架,工作原理是将输入数据切分成多个小数据块,然后分配给不同的计算节点进行并行计算,简化了分布式编程的复杂性。
  • YARN(分布式资源调度系统,Hadoop2.0 加入了 YARN)
    • YARN 作为资源管理层,负责集群资源的分配和任务的调度。

这三个核心组件相互协作,构成了完整的 Hadoop 生态系统,Hadoop 生态系统得以实现大规模数据的存储、计算和资源调度。

下面我们来详细了解一下这三个核心组件。

1. HDFS

HDFS 全称是 Hadoop Distributed File System,是 Hadoop 的分布式文件系统。

1.1. HDFS 的核心组成

HDFS 采用主从架构,包括一个主节点(NameNode)和多个从节点(DataNode)。NameNode 负责管理文件系统的命名空间和数据块的映射关系,而 DataNode 负责存储实际的数据块。

HDFS 三大重要角色:

  • HDFS Client(客户端):HDFS Client 是与 HDFS 交互的用户或应用程序。客户端负责向 HDFS 发送读取和写入文件的请求,以及管理文件系统的元数据信息。客户端通过 Hadoop 提供的 API(如 Java API、命令行工具等)与 HDFS 进行通信,实现对文件的操作。
  • NameNode(名称节点):NameNode 是 HDFS 中的主节点,负责管理文件系统的命名空间和数据块的映射关系。NameNode 维护文件系统的元数据信息,包括文件和数据块的映射关系、文件的权限和属性等。NameNode 还负责协调和监控 DataNode 的活动,并处理客户端的文件系统操作请求。
  • DataNode(数据节点):DataNode 是 HDFS 中存储数据块的节点。每个 DataNode 负责存储实际的数据块,并定期向 NameNode 报告自身的存储情况。DataNode 负责处理客户端的读取和写入请求,以及数据块的复制和恢复操作。

1.2. HDFS 的数据读取和写入流程简述

  • 数据写入流程
    1. 客户端请求:HDFS 客户端向 NameNode 发送写入文件的请求。
    2. NameNode 处理:NameNode 检查文件系统的元数据信息,确定文件的写入位置。
    3. 数据块分配:NameNode 为文件分配数据块,并返回给客户端数据块的位置信息。
    4. 数据写入:客户端将数据分成数据块,并按照 NameNode 返回的位置信息将数据块写入对应的 DataNode。
    5. 数据复制:DataNode 接收到数据块后,根据复制策略将数据块复制到其他 DataNode,以实现数据的冗余备份。
      • DataNode 数据写入完成后,HDFS Client 会根据 HDFS 的复制策略(通常是默认的副本数设置)决定将数据块复制到其他 DataNode 上。客户端会向 NameNode 请求其他 DataNode 的位置信息,并将数据块复制到这些 DataNode 上。复制的过程是在客户端和各个 DataNode 之间直接进行的,客户端负责协调和控制数据块的复制操作。
    6. 确认写入:客户端完成数据块的写入后,向 NameNode 发送写入完成的确认信息。
    7. 元数据更新:NameNode 更新文件系统的元数据信息,包括文件的大小、数据块的位置等。
  • 数据读取流程
    1. 客户端请求:HDFS 客户端向 NameNode 发送读取文件的请求。
    2. NameNode 处理:NameNode 检查文件系统的元数据信息,确定文件的数据块位置。
    3. 数据块读取:客户端根据 NameNode 返回的数据块位置信息,直接从对应的 DataNode 读取数据块。
    4. 数据合并:客户端将读取的数据块合并成完整的文件,读取完成。

1.3. HDFS 的优缺点

  • 优点:
    • 高可靠性和容错性:HDFS 通过数据复制和冗余备份实现数据的高可靠性和容错性,即使某个节点发生故障,数据仍然可用。
    • 数据本地性:HDFS 支持数据本地性原则,即数据处理尽量在数据所在的节点上进行,减少数据传输和网络开销。(通过移动计算任务而不是移动数据。它会把数据位置暴露给计算框架。)
    • 高扩展性:HDFS 具有良好的横向扩展性,可以轻松地扩展到成百上千台服务器,处理大规模数据存储和处理需求。
    • 适用于大文件存储:HDFS 适用于存储大文件和大规模数据集,能够有效管理大文件的存储和访问。
    • 流式文件访问:一次写入,多次读取。文件一旦写入不能修改,只能追加。它能保证数据的一致性。
  • 缺点:
    • 不适合小文件存储:HDFS 不适合存储大量小文件,因为小文件会占用过多的元数据空间和存储资源,影响系统性能。(这里的小文件是指小于 HDFS 系统的 Block 大小的文件,Hadoop 3.x默认128M 。)
    • 延迟较高:由于数据的冗余备份和复制,HDFS 在数据写入和读取时可能会有一定的延迟,不适合对实时性要求较高的应用。
    • 并发写入、文件随机修改:一个文件只能有一个写,不允许多个线程同时写。仅支持数据append(追加),不支持文件的随机修改。

1.4. Namenode HA 详解

在 HDFS 中,NameNode 将文件系统的元数据信息存储在内存中的数据结构中,以便快速访问和处理文件系统的元数据操作。这些元数据信息包括文件的路径、大小、权限、所有者、数据块的位置和复制情况等。通过将元数据信息保存在内存中,NameNode 能够快速响应客户端的文件系统操作请求,如文件的创建、删除、重命名等。

虽然将元数据储存到内存中响应速度快,但存在较大的数据丢失风险,所有我们可以引入一个备份节点(Standby NameNode)和 JournalNodes 集群来实现元数据备份和 NameNode 节点高可用。

1.4.1. Namenode 元数据备份流程

  1. 每次 Active NameNode(主节点)修改一次元数据都会生成一条 edits log,除了写入本地磁盘文件,还会写入 JournalNodes 集群。
  2. 然后 Standby NameNode 就可以从 JournalNodes 集群拉取 edits log,应用到自己的内存文件系统里,跟 Active NameNode 保持一致。
  3. 然后每隔一段时间,Standby NameNode 都把自己内存里的元数据写一份到磁盘上的,得到一份完整的元数据(fsimage)。这个操作就是所谓的 checkpoint 检查点操作。
  4. 然后把这个 fsimage 上传到 Active NameNode 本地磁盘,接着 Active NameNode 清空掉旧的 edits log 文件。
  5. 然后 Active NameNode 将接收到的新的修改元数据的请求,再写入新的 edits log 和 JournalNodes 集群。
  6. 如果此时,Active NameNode 重启了,只需要将 fsimage 直接读到内存里,并恢复新的 edits log 里的少量修改到内存里就完成了元数据的恢复。

1.4.2. Namenode 主备节点切换

由上述流程可知,Standby NameNode 与 Active NameNode 节点内存中有相同的元数据,所有可以将 Standby NameNode 节点作为 Active NameNode 故障时的备用节点。

使用到的组件:

  • 主备切换控制器 ZKFC( 全称 ZooKeeper Failover Controller,它是用于在使用 ZooKeeper 进行高可用性和故障转移的分布式系统中的一个组件)
    • ZKFailoverController 作为独立的进程运行,对 NameNode 的主备切换进行总体控制。ZKFailoverController 能及时检测到 NameNode 的健康状况,在主 NameNode 故障时借助 Zookeeper 实现自动的主备选举和切换。
    • ZKFailoverController 作为 NameNode 机器上一个独立的进程启动 (在 hdfs 启动脚本之中的进程名为 zkfc),启动的时候会创建 HealthMonitor 和 ActiveStandbyElector 这两个主要的内部组件,ZKFailoverController 在创建 HealthMonitor 和 ActiveStandbyElector 的同时,也会向 HealthMonitor 和 ActiveStandbyElector 注册相应的回调方法。
      • HealthMonitor 主要负责检测 NameNode 的健康状态,如果检测到 NameNode 的状态发生变化,会回调 ZKFailoverController 的相应方法进行自动的主备选举。
      • ActiveStandbyElector 主要负责完成自动的主备选举,内部封装了 Zookeeper 的处理逻辑,一旦 Zookeeper 主备选举完成,会回调 ZKFailoverController 的相应方法来进行 NameNode 的主备状态切换。
  • Zookeeper 集群:为主备切换控制器提供主备选举支持。

NameNode 实现主备切换的流程:

  1. HealthMonitor 初始化完成之后会启动内部的线程来定时调用对应 NameNode 的 HAServiceProtocol RPC 接口的方法,对 NameNode 的健康状态进行检测。
  2. HealthMonitor 如果检测到 NameNode 的健康状态发生变化,会回调 ZKFailoverController 注册
    的相应方法进行处理。
  3. 如果 ZKFailoverController 判断需要进行主备切换,会首先使用 ActiveStandbyElector 来进行自
    动的主备选举。
  4. ActiveStandbyElector 与 Zookeeper 进行交互完成自动的主备选举。
  5. ActiveStandbyElector 在主备选举完成后,会回调 ZKFailoverController 的相应方法来通知当前的
    NameNode 成为主 NameNode 或备 NameNode。
  6. ZKFailoverController 调用对应 NameNode 的 HAServiceProtocol RPC 接口的方法将 NameNode 转换为 Active 状态或 Standby 状态。

2. YARN

Apache Yarn(Yet Another Resource Negotiator 的缩写)是 Hadoop 集群资源管理器系统,它负责分
配和管理集群中的资源。Yarn 将集群资源视为一个资源池,并将应用程序所需的资源封装成资源容器
(Resource Container),如内存、CPU等。Yarn可以根据应用程序的需求动态地分配资源,使得集群
资源得到最大化的利用。

YARN 架构包括 ResourceManager(资源管理器)、NodeManager(节点管理器)和 ApplicationMaster (应用管理器)三个核心组件。

2.1. Yarn 特点

  • 灵活性:YARN 支持多种计算框架,如 MapReduce、Spark、Hive 等,具有较高的灵活性和通用性。
  • 资源隔离:YARN 通过容器(Container)实现资源隔离,每个应用程序运行在独立的容器中,避免资源冲突和干扰。
  • 高可用性:YARN 的 ResourceManager 和 NodeManager 都支持高可用性配置,保证集群的稳定性和可靠性。

2.2. Yarn 的应用场景

YARN 适用于大规模数据处理场景,如批处理、实时处理、机器学习等,支持多种计算框架和应用程序的并行计算和资源管理。

2.3. Yarn 三大核心组件详解

2.3.1. ResourceManager(RM)

RM 是一个全局的资源管理器,管理整个集群的计算资源,并将这些资源分配给应用程序。主要功能包
括:

  • 与客户端交互,处理来自客户端的请求。
  • 启动和管理 ApplicationMaster 组件,并在它运行失败时重新启动它。
  • 管理 NodeManager 组件 ,接收来自 NodeManager 的资源汇报信息,并向 NodeManager 下达管理指令。
  • 资源管理与调度,接收来自 ApplicationMaste r组件的资源申请请求,并为之分配资源。

RM 关键配置参数:

  • 最小容器内存: yarn.scheduler.minimum-allocation-mb
  • 容器内存增量: yarn.scheduler.increment-allocation-mb
  • 最大容器内存: yarn.scheduler.maximum-allocation-mb
  • 最小容器虚拟 CPU 内核数量: yarn.scheduler.minimum-allocation-mb
  • 容器虚拟 CPU 内核增量: yarn.scheduler.increment-allocation-vcores
  • 最大容器虚拟 CPU 内核数量: yarn.scheduler.maximum-allocation-mb
  • ResourceManager Web 应用程序 HTTP 端口: yarn.resourcemanager.webapp.address

2.3.2. ApplicationMaster(AM)

负责管理和监控单个应用程序(Application)的执行过程。每个在 YARN 上运行的应用程序都会有一个对应的 ApplicationMaster 实例,用于协调应用程序的资源请求、任务调度和监控。

主要功能包括:

  • ApplicationMaster 负责向 ResourceManager 请求所需的计算资源(容器),并协调资源的分配和释放。
  • ApplicationMaster 将应用程序的任务分配给各个容器,并监控任务的执行状态和进度。
  • ApplicationMaster 负责处理应用程序的失败和异常情况,如重新启动失败的任务、处理节点故障等。
  • ApplicationMaster 定期向 ResourceManager 发送应用程序的状态报告,包括任务执行情况、资源利用情况等。

AM 关键配置参数:

  • ApplicationMaster 最大重启次数: yarn.resourcemanager.am.max-attempts。
    • 当 ApplicationMaster 在执行过程中失败或终止时,ResourceManager 会尝试重新启动 ApplicationMaster,以尝试恢复应用程序的执行。该参数定义了最大的重试次数,超过这个次数后将不再尝试重新启动 ApplicationMaster,应用程序将被认定为执行失败。
  • ApplicationMaster 监控过期时间间隔:yarn.am.liveness-monitor.expiry-interval-ms。
    • 即 ResourceManager 用于监控 ApplicationMaster 存活状态的时间间隔

2.3.3. NodeManager(NM)

运行在集群中的每个节点上,负责管理和监控该节点上的资源,执行容器(Container)中的任务,并与 ResourceManager 协调资源的分配和释放。

主要功能包括:

  • 启动和监视节点上的计算容器(Container)
  • 以心跳的形式向RM汇报本节点上的资源使用情况和各个Container的运行状态(CPU和内存等资源)
  • 接收并处理来自AM的Container启动/停止等各种请求

NM 关键配置参数:

  • 节点内存: yarn.nodemanager.resource.memory-mb
  • 节点虚拟 CPU 内核: yarn.nodemanager.resource.cpu-vcores
  • NodeManager Web 应用程序 HTTP 端口: yarn.nodemanager.webapp.address

2.4. Yarn 工作流程

  1. 客户端程序向 ResourceManager 提交应用并请求一个 ApplicationMaster 实例,ResourceManager 在应答中给出一个 applicationID 以及有助于客户端请求资源的资源容量信息。
  2. ResourceManager 找到可以运行一个 Container 的 NodeManager,并在这个 Container 中启动
    ApplicationMaster 实例。
  3. ApplicationMaster 向 ResourceManager 进行注册,注册之后客户端就可以查询 ResourceManager 获得自己 ApplicationMaster 的详细信息,以后就可以和自己的 ApplicationMaster 直接交互了。在注册响应中,ResourceManager 会发送关于集群最大和最小容量信息。
  4. 在平常的操作过程中,ApplicationMaster 根据r esource-request 协议向 ResourceManager 发送resource-request 请求,ResourceManager 会根据调度策略尽可能最优的为 ApplicationMaster 分配container 资源,作为资源请求的应答发给 ApplicationMaster。
  5. 当 Container 被成功分配之后,ApplicationMaster 通过向 NodeManager 发送 container-launch-specification 信息来启动 Container, container-launch-specification 信息包含了能够让 Container 和ApplicationMaster 交流所需要的资料,一旦 container 启动成功之后,ApplicationMaster 就可以检查他们的状态,Resourcemanage r不在参与程序的执行,只处理调度和监控其他资源, Resourcemanager 可以命令 NodeManager 杀死 container。
  6. 应用程序的代码在启动的 Container 中运行,并把运行的进度、状态等信息通过 application-specific协议发送给 ApplicationMaster,随着作业的执行,ApplicationMaste r将心跳和进度信息发给ResourceManager,在这些心跳信息中,ApplicationMaster 还可以请求和释放一些 container。
  7. 在应用程序运行期间,提交应用的客户端主动和 ApplicationMaster 交流获得应用的运行状态、进度更新等信息,交流的协议也是 application-specific 协议。
  8. 一但应用程序执行完成并且所有相关工作也已经完成,ApplicationMaster 向 ResourceManager 取
    消注册然后关闭,用到所有的 Container 也归还给系统,当 container 被杀死或者回收,
    Resourcemanager 都会通知 NodeManager 聚合日志并清理 container 专用的文件。

3. MapReduce(了解)

MapReduce 是一种编程模型和处理框架,用于处理大规模数据集并实现并行计算。

工作原理:

例如在处理一个复杂、计算量大、耗时长的任务时使用单台服务器无法计算或无法在较短时间内计算出结果时,可将此大任务切分成一个个小的任务,小任务分别在不同的服务器上并行的执行;最终再汇总每个小任务的结果。

工作阶段:

MapReduce 将数据处理任务主要分为两个阶段:Map 阶段和 Reduce 阶段。

  • Map 阶段:在 Map 阶段,输入数据集被划分为若干个数据块,每个数据块由一个 Map 任务处理。Map 任务将输入数据映射为键值对(key-value pairs)。
  • Shuffle 阶段:在 Shuffle 阶段,Map 任务的输出结果按照键进行排序,并分区传递给 Reduce 任务。
  • Reduce 阶段:在 Reduce 阶段,Reduce 任务对相同键的数据进行聚合和处理,生成最终的输出结果。

4. Spark