1. HDFS
1.1 HDFS 简介
HDFS 是分布式文件系统,它默认的存储单元是 64M 的数据块,包括 NameNode,DataNode,Secondary NameNode。
- NameNode(元数据节点)
- 管理 HDFS 的文件目录树
- 管理 Block 的存储信息,如一个文件对应块的名字、存储位置、每一个文件备份多少
- 处理客户端的读写请求
- DataNode(数据节点):
- DataNode 是真正存储数据的地方,负责数据读写的执行操作。
- 定时向 NameNode 汇报存储数据块的信息
- Secondary NameNode(从元数据节点):
- 周期性地合并 NameNode 的 fsimage 和 editlog,防止日志文件过大
- 必要时可以辅助恢复 NameNode
1.2 fsimage 和 editlog 定义及合并过程
- fsimage 是镜像文件,是元数据在某个时间段的快照
- edits 记录了生成快照之后的一系列写操作。
HDFS 第一次启动时,会创建一份 fsimage 和 edits 文件,后续每一次客户端操作时,会先记录客户端执行的操作到 Edits 文件中,然后再更新内存中对应的目录树结构。如果不是第一次启动,直接加载 fsimage 和 edits 文件到内存中。
也就是说,内存中的元数据信息是完整的。前面生成的快照 Fsimage 只是元数据的一部分,执行完 Edits 文件中相关操作才能与内存中元数据相同。
SecondaryNameNode 具体干什么事情?
当 HDFS 运行一段时候重启后,需要将 fsimage 加载到内存中,并把 edits 文件中的操作执行一遍,才是完整的元数据信息。 假如一直追加操作,那么日志文件会非常庞大,重启时会很耗时。因此,SecondaryNameNode 可以定期将 fsimage 和 edits 合并成一个新的 fsimage,减少 HDFS 重启时间。
合并过程:
- SNN 周期性通过 getEditLog 获取 edits 的大小,当达到合并大小的时候进行合并
- SNN 向 NN 请求执行 checkpoint 操作,NN停止使用 edits 文件,并生成一个新的临时的 edits.new 文件
- SNN 通过 http get 获取 NN 的 fsimage 和 edits 文件。
- SNN 将 fsimage 导入内存,并逐个执行 edits 中的操作,生成新的 fsimage.ckpt 文件
- SNN 执行结束后,向 NN 发送 http 请求,告诉它合并结束。然后 NN 通过 http post 获取新的 fsimage.ckpt 文件
- NN 将新的 fsimage.ckpt 文件替换为 fsimage 文件,将 edits.new 文件替换为 edits 文件
1.3 HDFS 读流程
- 初始化 DistributedFileSystem 对象,然后客户端用 DFS 对象的 open 函数打开文件
- DFS 对象用 RPC 调用 NameNode,得到文件的数据块信息。对于每一个数据块,NameNode 返回保存数据块的 DataNode的地址
- DFS 对象返回 FSDataInputStream 给客户端,用来读取数据,客户端调用 InputStream 的 read() 函数开始读取数据
- InputStream 连接最近的保存第一个数据块的 DataNode,DataNode 将数据返回给客户端。在读取过程中,如果客户端在和 DataNode 通信出现错误,则尝试连接下一个最近的保存这个数据块的 DataNode
- 当一个数据块读取完毕之后,InputStream 关闭和这个 DataNode 的连接,然后继续连接最近的保存下一个数据块的 DataNode
- 当客户端读取完毕后,调用 InputStream 的 close() 函数
1.4 HDFS 写流程
- 客户端调用 DistributedFileSystem 对象的 create 方法,创建一个 FSDataOutputStream 对象
- DFS 对象用 RPC 调用 NameNode,NameNode 在文件目录树中创建一个新的文件夹
- DFS 对象向 NameNode 请求上传第一个 Block,然后 NameNode 返回一组 DataNode 的地址(如 DN1, DN2, DN3)
- 客户端通过 OutputStream 向第一个 DN1 上传数据,DN1 收到请求会继续调用 DN2,然后 DN2 调用 DN3,从而建立一个通信管道。
- 客户端首先将 Block 从磁盘写到 OutputStream 内部的 Buffer 里,并且 Block 被分割成一个个 Packet 数据包(即数据队列)
- 以 Packet 为单位,客户端开始往 DN 上传第一个 Block 的所有 Packet
- 第一个 Block 传输完成后,客户端再次请求 NameNode 上传第一个 Block,重复 3~7
- 客户端传输完毕后,调用 OutputStream 的 close 函数
- 客户端调用 DFS 对象的 complete 方法,通知 NameNode 写入成功
1.5 NameNode 的 HA 实现
HA 的 NameNode 主要分为 共享 Edits 文件机制 和 ZKFC 对 NameNode 状态的控制 。
-
共享 Edits 文件机制:
- 集群中存在多个 NameNode,这些 NN 都有状态,分为 active 和 standby
- 然后各个 NN 之间通过 JournalNode 集群共享 Edits 文件。active NN 将 Edits 文件写入 JournalNode 集群,而 standby NN 则定期读取 Edits 文件来保持和 active NN 的同步
-
ZKFC 对 NameNode 状态的控制 :
- 每一个 NN 运行一个轻量级的故障转移控制器 ZKFC,用于监视和控制 NN 进程。ZKFC 是基于 zookeeper 实现的。启动的时候会创建 HealthMonitor 和 ActiveStandbyElector 这两个组件。
- HealthMonitor :主要负责监测 NN 的健康状态,如果监测到 active NN 的状态发生变化,会回调 ZKFC 的相应方法进行自动的主备选举。
- ActiveStandbyElector:主要负责完成自动的主备选举,内部封装了 zookeeper 的处理逻辑。一旦 zookeeper 主备选举完成,会自动回调 ZKFC 的相应方法进行 NN 的主备状态切换
- 每一个 NN 运行一个轻量级的故障转移控制器 ZKFC,用于监视和控制 NN 进程。ZKFC 是基于 zookeeper 实现的。启动的时候会创建 HealthMonitor 和 ActiveStandbyElector 这两个组件。
脑裂(split-brain):
在实际中,NameNode 可能会出现这种情况,NameNode 在垃圾回收(GC)时,可能会在长时间内整个系统无响应,因此,也就无法向 zk 写入心跳信息,这样的话可能会导致临时节点掉线,备 NameNode 会切换到 Active 状态,这种情况,可能会导致整个集群会有同时有两个 NameNode,这就是脑裂问题。
Hadoop 目前主要提供两种隔离(fencing)措施,通常会选择第一种:
- sshfence:通过 SSH 登录到目标机器上,执行命令将对应的进程杀死;
- shellfence:执行一个用户自定义的 shell 脚本来将对应的进程隔离。
如何判断脑裂 :
ActiveStandbyElector 在 zookeeper 中创建了 active NN 后,还会创建一个对应的持久节点,这个节点保留了该 active NN 的地址信息。
如果该 active NN 在正常状态下关闭了 zk 连接,会一起删除这个持久节点。但如果该 active NN 在异常状态下关闭了 zk 连接,则持久节点会保留下来。
假如发生了脑裂,另一个 NN 成功选为 active NN 后,会注意到保留下来的持久节点,从而会回调 ZKFC 的方法对旧的 active NN 进行 fencing。
1.6 在向 HDFS 中写数据时,当写某一个副本时出错怎么处理?
- 首先会关闭管道
- 将已经发送到管道中但是没有收到确认的数据包重新写回数据队列,这样无论哪个节点发生故障,都不会发生数据丢失。
- 当前正常的 DN 被赋予一个新的版本号(NN 可以获得最新时间戳版本),这样故障的 DN 在恢复后,由于版本信息不对会被删除。
- 在当前正常的 DN 中选择一个 main DN,并与其他正常的 DN 通信,获取每个 DN 当前数据块的大小,从中选择一个最小的值,将每个正常的 DN 同步到该大小,然后重新建立管道。
- 在新的管道中删除故障节点,并把数据写入新的管道。
- 当文件关闭后, NN 发现副本数量不足时,会在另一个 DN 上创建一个新的副本。
1.7 简述联邦 HDFS
联邦 HDFS 允许创建多个 NN 各自管理文件系统命名空间的一部分,每个 NN 维护一个命名空间,不同 NN 之间的命名空间相互独立。每个 DN 都需要注册到每个 NN。
2. MapReduce 和 YARN
2.1 YARN 介绍
MR1.0 和 2.0 工作流程的主要区别就是 YARN 的引入。在 YARN 中将 MR1.0 版本中的 JobTracker 的两个主要功能分离成单独的组件,这两个功能分别是资源管理 ResourceManager 和任务调度 ApplicationMaster。
YARN 中的主要角色包括:ResourceManager、ApplicationMaster、NodeManager
- ResourceManager:负责启动每一个 Job 所属的 ApplicationMaster;监控 ApplicationMaster 和 NodeManager 的存在情况;负责协调集群上计算资源的分配。
- ApplicationMaster:负责运行 MR 任务的调度和协调,并负责报告任务状态。
- NodeManager:负责启动和管理节点中的容器
2.2 MR1.0 的 Job 提交流程
MR1.0 的角色包括:JobTracker、TaskTracker。JobTracker 负责协调 Job 的运行,而 TaskTracker 负责 Job 的执行。
MapReduce 过程:
- 客户端向 JobTracker 请求一个新的 Job,然后 JobTracker 会向客户端返回 Job 相关资源的提交路径和 JobID
- 客户端将 Job 的相关资源提交到 HDFS 中,并告诉 JobTracker 资源已经提交完毕,准备执行
- JobTracker 从 HDFS 中获取客户端的输入分片,每个分片创建一个 Map 任务
- JobTracker 将任务放入内部的任务队列,由 作业调度器 进行调度
- TaskTracker 通过心跳与 JobTracker 保持通信,报告自己的状态,以及是否准备好运行一个 task。如果准备好,JobTracker 就从任务队列中分配一个 task 给 TaskTracker
- TaskTracker 从 HDFS 中获取任务的相关资源,并创建一个 TaskRunner 实例来运行
- TaskRunner 启动一个新的 JVM 来运行每个任务
2.3 MR2.0 的 Job 提交流程
MapReduce 过程:
- 运行 hadoop jar 命令后产生一个 RunJar 进程,客户端向 RM 申请执行一个 Job
- RM 收到请求后会向客户端返回 Job 相关资源的提交路径以及 JobID
- 客户端将 Job 的相关资源提交到 HDFS 中
- 客户端通知 RM 资源已经提交完毕
- RM 将这个 Job 加入调度队列
- NM 通过与 RM 的心跳连接,从 RM 的调度队列中获取到新的任务
- RM 为 NN 创建容器 Container,并在容器中启动 MRAppMaster 进程
- MRAppMaster 进程去 HDFS 上下载 Job 的相关资源
- MRAppMaster 负责分配在哪些 NM 上运行 Map 任务和 Reduce 任务,并向 RM 申请创建 Map Task 和 Reduce Task 的容器
10.Job 任务执行完毕后,MRAppMaster 向 RM 注销自己,让 RM 回收资源
2.4 MapReduce 的 Shuffle 过程
Shuffle 阶段主要负责将 Map 端生成的数据传递给 Reduce 端,因此 Shuffle 分为在 Map 端的过程和在 Reduce 端的过程,具体过程如下:
Map 端 :
- Map Task 将 KV 对放到环形缓冲区中(默认100M)
- 环形缓冲区达到一定阈值(环形缓冲区大小的80%)时,会将缓冲区中的数据溢写到磁盘中 ,这个过程可能会溢写多个文件
- 多个溢写文件会被合并成一个大的溢出文件(归并排序)
- 在溢写过程和合并过程中,需要调用 Partitiner 进行分区,并且同一个分区内进行排序(快速排序)
- 合并成大文件之后,Map 端的 Shuffler 过程就结束了
Reduce 端 :
- Reduce Task 会通过 HTTP 向各个 Map Task 获取它所对应分区的数据
- 获取来的数据首先会先放入到内存缓冲区中,当缓冲区达到一定阈值后,就会将缓冲区中的数据 Merge 到磁盘中(归并排序)
- 当该 Reducer 的所有 Map 输出全部拷贝完成,就会在磁盘中生成若干个文件(如果拖取的所有 Map 数据量都没有超出内存缓冲区,则数据就只存在于内存中),这时就开始执行合并操作(归并排序)
转载:https://blog.csdn.net/cys975900334/article/details/116802368