Hadoop-HDFS流程解析

Posted by SH on May 7, 2021

Hadoop-HDFS流程解析

  • hdfs数据写入流程
  • hdfs数据读取流程
  • hdfs如何保证数据完整性
  • hdfs的块大小为什么默认是64mb(128mb)

1.HDFS写数据

流程图

HDFS写数据

具体步骤

  1. 客户端调用DistributedFileSystem模块向NameNode请求上传文件,可以指定参数(dfs.replication:3;block.size:128m)。
  2. NameNode会检查权限、检查目标文件和父目录是否已存在、检查文件租约(lease),再返回是否可以上传。
  3. 假设文件为200M,客户端请求上传第一个 Block ,希望得到DataNode服务器位置。
  4. NameNode返回3个DataNode节点(考虑数据可靠性、写入效率、负载均衡),分别为dn1、dn2、dn3,用它们存储数据。
  5. 客户端通过FSDataOutputStream模块请求dn1建立上传数据通道,dn1收到请求会继续请求dn2,然后dn2请求dn3,直到将这个通信管道Pipeline建立完成。
  6. dn3、dn2、dn1逐级应答客户端。
  7. 客户端开始往dn1上传第一个Block(先从磁盘读取数据放到一个本地内存缓存),以Packet(64kb)为单位,dn1收到一个Packet就会传给dn2,dn2传给dn3;dn1每传一个packet会放入一个应答队列等待应答(类似队列,以Packet为单位),客户端通过dn返回的ack判断是否写入成功。
  8. 当一个Block(0-128M)传输完成之后,客户端再次请求NameNode上传第二个Block的服务器。(重复执行3-7步)。
  9. 向NameNode汇报上传完毕。

    注意事项

    • DataNode位置选择,以默认3副本为例:第一个副本是最近的一般是它自己;第二个副本选择同一机架(同一路由)的不同节点;第三个副本是另一机架的随机节点。
    • 节点距离:根据网络拓扑结构来计算距离。
    • 数据传递以包为单位,第一个节点收到一个包,就把包传递给下一个DataNode。并不是等数据传完,再传递。
    • 失败情况:配置最小写入副本数(默认1),达到就成功,如果失败就向namenode重试。
    • 切分Block:

2.HDFS读数据

流程图

HDFS读数据

具体步骤

  1. 客户端调用DistributedFileSystem模块向NameNode请求下载文件。
  2. NameNode会检查目标文件是否存在,再通过查询元数据,返回文件块所在的DataNode地址。
  3. 客户端通过FSDataInputStream模块向dn1(就近挑选)请求读取 Block1
  4. DataNode开始传输数据给客户端(从磁盘里面读取数据输入流,以Packet为单位来做校验)。客户端以Packet为单位接收,先在本地缓存,然后写入目标文件。
  5. 当一个Block(0-128M)传输完成之后,客户端再次请求下载Block2。(重复执行2-4步)。
  6. 向NameNode汇报下载完毕。

    注意事项

    • 如果块的第一个副本请求失败,会向第二个副本请求,依次类推。

3.NameNode和SecondaryNameNode

NameNode

作用:

  • Namespace管理:负责管理文件系统中的树状目录结构以及文件与数据块的映射关系;
  • 块信息管理:负责管理文件系统中文件的物理块与实际存储位置的映射关系BlocksMap
  • 集群信息管理:机架信息,datanode信息;
  • 集中式缓存管理:从Hadoop2.3开始,支持datanode将文件缓存到内存中,这部分缓存通过NN集中管理。

存储结构:

  • 内存:Namespace数据、BlocksMap数据,其他信息;
  • 文件:
    • 已持久化的namespace数据:FsImage;
    • 未持久化的namespace操作:Edits。

流程图

HDFS写数据

具体步骤

第一阶段:NameNode

  1. 第一次启动NameNode(格式化) 后,会创建Fsimage(镜像文件)Edits(编辑日志) 文件。以后启动,会直接加载镜像文件和编辑日志到内存,此时会进行合并操作。
  2. 假设此时客户端提出了增删改的请求。
  3. NameNode记录之前的编辑日志(edits_n),更新新日志到滚动日志(edits_inprogress_n) 中。
  4. 日志记录完毕后,NameNode在内存中对数据进行增删改。

第二阶段:SecondaryNameNode

  1. Secondary NameNode向NameNode询问是否需要CheckPoint
  2. 如果需要,Secondary NameNode请求执行CheckPoint。
  3. NameNode滚动日志。
  4. 将滚动前的编辑日志(edits_001)和镜像文件(fsimage)拷贝到Secondary NameNode。
  5. Secondary NameNode加载编辑日志和镜像文件到内存,并合并
  6. 合并后,生成新的镜像文件fsimage.chkpoint。
  7. 拷贝fsimage.chkpoint到NameNode。
  8. NameNode将fsimage.chkpoint重新命名成fsimage。

注意事项

  • Fsimage 和 Edits文件?

fsimage是NameNode内存中元数据序列化后形成的文件。Edits中记录客户端更新元数据信息的每一步操作。每次执行增删改时,先改日志再改文件。好处是:如果保证中途gg,可以保证操作不丢失,便于复原。

  • 为啥要Secondary NameNode?

首先要知道只有NameNode重启时,edit.log才会合并到fsimage文件中,所以运行时间久了就会有3个问题:edis.log文件会变的很大;NameNode下次重启会花费很长时间;fsimage文件文件很旧,如果中途挂掉就很弱智。

为了解决上述问题,SecondaryNameNode诞生,每隔一定时间辅助合并NameNode的edit.log到fsimage文件中。从上述流程图就可以发现,它做的就是这个。

  • 什么时候执行CheckPoint?

(1) 用户定时 (2)edit.log 满了

  • Secondary NameNode是热备份吗?

不是,可以发现Secondary NameNode合并的是滚动前的edis,它总是比NameNode的编辑日志少一点。

4.DataNode和NameNode

流程图

NameNode和DataNode

具体步骤

  1. DataNode启动后向NameNode注册
  2. NameNode告知注册成功
  3. DataNode周期性(1小时)的向NameNode上报所有的块信息。
  4. DataNode每3秒发送一次心跳,心跳返回结果带有NameNode给该DataNode的命令如复制块数据到另一台机器,或删除某个数据块。
  5. 超过10分钟没有收到心跳,表示该节点不可用。

    注意事项

    • 一个数据块在DataNode上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据(包括数据块的长度校验和 以及时间戳)。
    • 节点增加:新节点配置好后,自动向NameNode注册的。
    • 节点退役:NameNode可以通过白名单指定需要的节点;通过黑名单指定不要的节点。

5.HDFS如何保证数据完整性

  • 读取数据完整性
  • 写数据完整性
  • 磁盘完整性

(1)客户端写数据的时候,将数据和校验和发送到一系列由datanode组成的管线,管线中的最后一个datanode负责校验校验和,如果发现数据校验和对不上,则抛出异常,hdfs会以特定方式处理,例如重试这个操作。

(2)读数据时也会验证校验和,把读出来的数据和读出来的校验和校验,确保读出的数据是正确的,每个datanode都保持着一个用于验证的校验和日志,日志中保存着每个数据块的验证时间,客户端每验证完一个数据块,就会更新日志。

(3)如果在读取数据的过程中,如果检测到数据校验错误,首先会通知namenode这个已损坏数据块以及正在读取的datanode,再抛出ChecksumException异常。namenode将这个数据块副本标记为已损坏,不再将客户端请求发送到这datanode上,并且会把这个数据块的一个副本复制到另一个datanode上,这样数据块的副本因子又可以变成期望水平,默认为3,最后已损坏的数据块会被删除

(4)此外datanode也会在后台线程中运行一个线程定期检查datanode上的所有数据块,避免磁盘损坏

6.块默认是64/128mb?

(1)为什么不能远少于64MB(或128MB或256MB) (普通文件系统的数据块大小一般为4KB)

  • 减少硬盘寻道时间(disk seek time)

HDFS设计前提是支持大容量的流式数据操作,所以即使是一般的数据读写操作,涉及到的数据量都是比较大的。假如数据块设置过少,那需要读取的数据块就比较多,由于数据块在硬盘上非连续存储,普通硬盘因为需要移动磁头,所以随机寻址较慢,读越多的数据块就增大了总的硬盘寻道时间。当硬盘寻道时间比io时间还要长的多时,那么硬盘寻道时间就成了系统的一个瓶颈。合适的块大小有助于减少硬盘寻道时间,提高系统吞吐量。

  • 减少Namenode内存消耗

对于HDFS,他只有一个Namenode节点,他的内存相对于Datanode来说,是极其有限的。然而,namenode需要在其内存FSImage文件中中记录在Datanode中的数据块信息,假如数据块大小设置过少,而需要维护的数据块信息就会过多,那Namenode的内存可能就会伤不起了。

(2)为什么不能远大于64MB(或128MB或256MB)

这里主要从上层的MapReduce框架来讨论

  • Map崩溃问题:

系统需要重新启动,启动过程需要重新加载数据,数据块越大,数据加载时间越长,系统恢复过程越长。

  • 监管时间问题:

主节点监管其他节点的情况,每个节点会周期性的把完成的工作和状态的更新报告回来。如果一个节点保持沉默超过一个预设的时间间隔,主节点记录下这个节点状态为死亡,并把分配给这个节点的数据发到别的节点。对于这个“预设的时间间隔”,这是从数据块的角度大概估算的。假如是对于64MB的数据块,我可以假设你10分钟之内无论如何也能解决了吧,超过10分钟也没反应,那就是死了。可对于640MB或是1G以上的数据,我应该要估算个多长的时间内?估算的时间短了,那就误判死亡了,分分钟更坏的情况是所有节点都会被判死亡。估算的时间长了,那等待的时间就过长了。所以对于过大的数据块,这个“预设的时间间隔”不好估算。

  • 问题分解问题:

数据量大小是问题解决的复杂度是成线性关系的。对于同个算法,处理的数据量越大,它的时间复杂度也就越大。

  • 约束Map输出:

在Map Reduce框架里,Map之后的数据是要经过排序才执行Reduce操作的。想想归并排序算法的思想,对小文件进行排序,然后将小文件归并成大文件的思想,然后就会懂这点了….

References