Hadoop 之 HDFS
HDFS架构
- NameNode:负责管理和存储元数据;文件名、目录结构、文件属性(时间、副本、权限)、文件块列表,块所在DataNode(BlockId)。
- DataNode:本地文件系统中存储文件块数据、块校验和。
- SecondaryNameNode:定时将日志文件和镜像文件进行合并。
说明:谁启动的hdfs谁具有最高权限。
格式化namenode的过程中都做了什么?
- 创建文件存储的目录。
- 创建编辑日志和镜像文件。
- 创建UID。
不同进程间节点距离的计算: 节点、机架、集群、数据中心
特点:不同的节点之间建立连接需要先到达通信节点可以共同到达的最小交汇点,然后再走向目标节点。
-
同一节点的进程:0
-
同一机架上不同节点进程:2
-
同一集群不同机架节点上的进程:4
-
同一数据中心不同集群中节点上的进程:6
HDFS数据写入流程:
- 客户端将文件分块,默认块大小为128M,HDFS不支持并发写入,每次只能上传一个块。
- 客户端通过分布式文件系统 DistributeFileSystem 向 NameNode 发送上传文件请求,NameNode 收到请求后检查目标文件是否存,父目录是否存在,之后响应客户端可以上传文件。
- 客户端收到响应后向 NameNode 请求上传第一个块信息,并请求返回 DataNode,NameNode收到请求后根据文件的备份数量返回相应数量的 DataNode 节点。
- 客户端收到来自 NameNode 返回的节点信息,通过 FSDataOutPutStream 向离客户端最近的节点上传数据,第一个节点收到请求后会继续调用下一个的DataNode节点,然后下一个节点去调用自己的下一个节点,直到最后一个节点,将通信管道 PipeLine 建立,然后各个节点从后向前逐级应答客户端。
- 通信管道 PipeLine 建立完成后,客户端先将磁盘中的块信息读到内存,然后通过 FSDataOutPutStream开始以 Packet 为单位传送块数据,其中 Packet 为64K由 Chunk 组成,每个 Chunk 为 512B,并且每个 Chunk 还包含了4B的 crc 校验信息,共516B。当 Packet 被 Chunk 填满以后就将 Packet放入到应答队列 DataQueue 队列中等待,再从该队列中将 Packet 取出存入另一个队列 ACKQueue 队列中,然后将该 Patcket 发送给离客户端最近的 DataNode 。
- 第一个 DataNode 收到数据后,会将该数据传递给下一个 DataNode,每个节点收到数据后都会逐级传递给下个节点直至 PipeLine 中的最后一个节点。并且在传输 Packet 的过程中,每向 DataNode发送一个 Packet数据客户端都会等待来自 DataNode 的应答响应,若响应则代表当前节点收来自客户端发送的数据,若没有响应时会将 ACKQueun 中的 Packet 数据重新放回到 DataQueue 队列中等待再次发送,避免了数据丢失。
- 当第一个Block 块信息传输完成后,客户端会再次请求 NameNode 上传第其他个 Block 块信息。
说明:
-
块大小的设置,受磁盘读写速度的影响,寻址时间为传输时间的1%为最佳状态,由于寻址时间为 10ms 所以传输时间为1S,而磁盘的传输速率约为 100MB/s 所以块大小约100M,但100不是2的整次幂,所以选离它较近的128M。如果块太小会导致文件被分的过多造成资源浪费;由于 MapReduce 的切片规则是默认是按照文件的块大小切分的,如果块太大了会导致切片过大会使 MapTask 的个数过少,单个 MapTask 的任务量过大,无法快速完成任务。
-
通信管道 PipeLine 的建立,如果在创建过程中其中某个节点没有应答,客户端会向 NameNode 重新请求 DataNode,NameNode 收到请求后会重新分配并发送新的 DataNode;如果在文件传输过程中,某个节点因为某种原因挂掉了,或者其他的原因该节点收不到数据没有应答,客户端会正常重新向其发送数据,再重复发一次之后还收不到应答则认为该节点不可用便会跳过该节点向其余的节点传送数据,传输完成之后,NameNode 在收到 DataNode 的上报信息时会发现少了一个备份,则会将其他节点上的文件自动备份一份。特别:如果是第一个节点有问题,则整个管道不会形成,或形成管道之后第一个节点有问题则直接导致任务失败。
-
每个 Chunk 都会包含4B的 crc 校验信息,所以每传128M的信息都会包含1M的 crc 校验信息。
-
HDFS不支持随机写,但支持追加写入。
HDFS读出数据流程:
-
客户端通过 DistributeFileSystem 向 NameNode 申请下载文件请求,NameNode 收到客户端下载请求后通过
查询文件的元数据找到文件所在的 DataNode ,然后返回包含所有该下载文件的 DataNode 给客户端。 -
客户端收到 NameNode 发送回来的 DataNode 信息后,会寻找据当前节点最近的 DataNode 节点请求下载文件。
-
DataNode 收到客户端下载请求后开始向客户端发送数据,先将磁盘中的块信息通过输入流读出到内存,然后以 Packet作为单位校验,传输给客户端。
-
客户端收到 Packet 后先将文件读入到内存然后通过输出流写出到磁盘存储。
NameNode和DataNode:
- 当开启 DataNode后,DataNode 会主动向 NameNode 申请注册。
- 注册成功后, DataNode周期性的每隔1小时(默认6)向NameNode上报所有块信息,通过 DataNode 的主动上报,NameNode可以检查文件的副本数以及副本信息,如果某个副本存在问题,NameNode 会等到 DataNode 主动上报信息后查询文件信息,发现文件错误或丢失时, 通知该 DataNode 节点将错误文件丢弃,并从其他 DataNode 节点将其重新备份。并且每3秒1次心跳,心跳中包含了NameNode带给 DataNade 的命令信息。
- 若3秒内没有收到来自 DataNode 的心跳,NameNode 不会立刻认为该节点挂掉了,而时会等待10分30秒的时间,如果超过该时间才会认为该节点不可用。
- 每个数据块在 DataNode 上以文件的形式存储在磁盘上,包括两个文件一个数据本身,另一个是元数据。
- NameNode 只记录了 Block与 DataNode 的映射关系,存储了一个 BlockId。
说明:
- 之所以让 DataNode 每次自己主动上报而不直接将 DataNode 信息存储在 NameNode 中是无法保证每次 NameNode中存储的 DataNode 信息是正确的,NameNode 每次读取 Block 信息时都会计算 CheckSum,如果计算的 CheckSum 与当时创建Block是的值不一样则代表Block损坏,会从其他节点备份。
- 每一个DataNode 都包含一套完整的块信息。
NameNode对元数据的管理:
-
Namenode对元数据管理采用了三种存储形式:
内存元数据、磁盘元数据镜像文件FSimage、数据操作日志文件edit(可以通过日志运算出元数据)。
NameNode、DataNode故障问题:
- NameNode故障:NameNode宕机后会导致Client无法访问,从而导致内存中的元数据丢失,但是由于我们有磁盘元数据镜像文件和操作日志文件,重启后可以重新读取数据。如果时服务器整体宕机了,需要查找服务器宕机原因,这样的问题我们再搭建集群的时候已经考虑到了,我们配置了HA高可用模式,当单节点故障后,StandBy的节点会变成leader。DataNode故障:DataNode的短暂宕机可以通过提前写好的脚本将它再次启动,如果DataNode长时间的宕机,NameNode会将该节点上的数据同步到其他服务器节点上,只需要将该节点上的数据删除掉重启即可。
NameNode和SecondaryNameNode:
- 第一次启动NameNode时需要格式化NameNode,并且会创建 Fsimage 和 Edits 文件,然后将镜像文件 Fsimage 和编辑日志Edits 加载到内存中。
- 当元数据有增删改请求时,会先写入到 Edits 编辑日志中并更新滚动日志,然后修改内存中的元数据。
- 每隔一分钟检查一次操作次数请求是否需要CheckPoint,并且直接带回是否检查的结果,若默认1小时计时时间到了,或 Edits中的数据存满100 万次时,会请求执行 CheckPoint。
- NameNode 会滚动正在写的 Edits,生成两个编辑日志,其中一个是目前位置的操作信息,另一个是新的编辑日志用来在编辑日志和镜像文件进行合并时对外提供服务,并将滚动前的日志和镜像文件拷贝到 SecondaryNameNode,然后 SecondaryNameNode 会将编辑日志和镜像文件加载到内存合并,然后生产新的镜像文件 Fsimage.Checkpoint 。
- 将新生产的镜像文件拷贝到 NameNode 中,并将其该名为 Fsimage 顶掉原来的镜像文件。
说明:
- SecondaryNameNode 不能作为 NameNode 的热备,因为 SecondaryNameNode 缺少了编辑日志和镜像文件在 SecondaryNameNode合并时 NameNode 对外提供服务是产生的新的操作产生的编辑日志。如果在合并过程中没有产生新的编辑日志,在 NameNode 挂掉时,可以用 SecondaryNameNode 暂时顶替 NameNode。
- NameNode中的元数据存储了两份,其中一份在内存,另一份在磁盘,对元数据进行修改时先写入到编辑日志,然后在加载到内存对元数据进行修改,然后定期的将内存中的镜像文件和编辑日志一起加载到SecondnaryNameNode 上进行合并。如果只讲元数据存储在磁盘里会导致每次对数据的修改会非常的慢,但如果只加载到内存中断电后数据会丢失。所以将元数据分为两份并通过添加编辑日志的方式对元数据进行修改,但是由于编辑日志的不断追加会导致编辑日志Edits文件会越来越大,从而导致 NameNode启动时加载编辑日志会很慢,并将其与镜像文件合并时的时间会很久,所以要定期的对内存中的镜像文件和编辑日志进行合并。
- 对 NameNode 中的元数据进行增删改操作时,需要先将操作写入操作日志,再加载到内存修改数据,而非直接加载到内存修改数据后再写入编辑日志,因为直接对元数据修改过后还没有来得及将操作写入操作日志时出现异常导致关机,下次开机再加载合并编辑日志和镜像文件时,会导致操作过后的数据丢失。
- 对 NameNode 中的元数据进行读操作时不会产生编辑日志,因为读操作不会对原有的数据进行改变。
HDFS如何保证数据安全?
- 存储在HDFS上的文件会切成128M的块存储在不同的节点数,每个块都有3个副本,DataNode以block为单位每3S向NameNode报告一次心跳,如果10分30秒没有是心跳,则会认为改节点挂掉,会从其他节点上备份数据到其他的节点,保证数据副本数量。DataNode每个1小时会像NameNode上报自己所有的快信息,HDFS每次启动会有安全模式,通过DataNode的自动上报信息计算Block的损坏率,当阈值<0.999f 时系统会进入安全模式,此时HDFS只能读不能写,HDFS元数据可以采用高可用HA备份。
黑白名单:用于集群访问权限的管理
-
黑名单:
集群退役的节点,将退役的节点添加到黑名单中会自动将该节点的资源重写分配。
-
白名单:
允许访问 NameNode的 DataNode节点,与Workers一致。
注意:退役后的节点数必须大于副本数,否则退役不成功。