HDFS深入学习总结

Posted Icedzzz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDFS深入学习总结相关的知识,希望对你有一定的参考价值。

参考链接:
https://zhuanlan.zhihu.com/p/265980039
尚硅谷视频

文章目录

HDFS架构

HDFS 采用 master/slave 架构。一个 HDFS 集群是由一个 Namenode(HA的情况除外) 和多个 Datanodes 组成。Namenode 是一个中心服务器,负责管理文件系统的名字空间(namespace) 以及客户端对文件的访问。集群中的 Datanode 一般是一个节点一个,负责管理它所在节点上的存储。 HDFS **暴露了文件系统的名字空间,用户能够以文件的形式在上面存储数据。**从内部看,一个文件其实被分成一个或多个数据块,这些块存储在一组 Datanode 上。Namenode 执行文件系统的名字空间操作,比如打开、关闭、重命名文件或目录。它也负责确定数据块到具体 Datanode 节点的映射。Datanode 负责处理文件系统客户端的读写请求。在 Namenode 的统一调度下进行数据块的创建、删除和复制。

HA架构

Active NameNode 和 Standby NameNode: 两台 NameNode 形成互备,一台处于 Active 状态,为主 NameNode,另外一台处于 Standby 状态,为备 NameNode,只有主 NameNode 才能对外提供读写服务,同一个时刻不应该出现两个节点都为Standby 状态或者都为Active状态,如有,那么需要进行排查问题所在(这里生产环境遇到多次问题,典型问题之一)。
主备切换控制器 ZKFailoverController: ZKFailoverController 负责定期的检测 NameNode 的健康状况,在主 NameNode(Active状态) 故障时借助 Zookeeper 实现自动的主备选举和切换。

**共享存储系统:**共享存储系统保存了 NameNode 在运行过程中所产生的 HDFS 的元数据。**主 NameNode 和 备 NameNode 通过共享存储系统实现元数据同步。**在进行主备切换的时候,新的主 NameNode 在确认元数据完全同步之后才能继续对外提供服务。(主备元数据同步问题,生产环境中也可能经常出现,典型问题之一)

NameNode 的主备切换实现

NameNode 主备切换主要由 ZKFailoverController、HealthMonitor 和 ActiveStandbyElector 这 3 个组件来协同实现:
ZKFailoverController 作为 NameNode 机器上一个独立的进程启动 (在 hdfs 启动脚本之中的进程名为 zkfc),启动的时候会创建 HealthMonitor 和 ActiveStandbyElector 这两个主要的内部组件。
HealthMonitor 主要负责检测 NameNode 的健康状态,如果检测到 NameNode 的状态发生变化,会回调 ZKFailoverController 的相应方法进行自动的主备选举。
ActiveStandbyElector 主要负责完成自动的主备选举,内部封装了 Zookeeper 的处理逻辑,一旦 Zookeeper 主备选举完成,会回调 ZKFailoverController 的相应方法来进行 NameNode 的主备状态切换。

ActiveStandbyElector 实现分析
Namenode(包括 YARN ResourceManager) 的主备选举是通过 ActiveStandbyElector 来完成的,ActiveStandbyElector 主要是利用了 Zookeeper 的写一致性和临时节点机制,
具体的主备选举实现如下:

  1. 在zk上面创建对应的节点
    如果 HealthMonitor 检测到对应的 NameNode 的状态正常,那么表示这个 NameNode 有资格参加 Zookeeper 的主备选举。如果目前还没有进行过主备选举的话,那么相应的 ActiveStandbyElector 就会发起一次主备选举,** 尝试在 Zookeeper 上创建一个路径为/hadoop-ha/ d f s . n a m e s e r v i c e s / A c t i v e S t a n d b y E l e c t o r L o c k 的 临 时 节 点 ∗ ∗ ( dfs.nameservices/ActiveStandbyElectorLock 的临时节点 ** ( dfs.nameservices/ActiveStandbyElectorLock(dfs.nameservices 为 Hadoop 的配置参数 dfs.nameservices 的值),Zookeeper 的写一致性会保证最终只会有一个 ActiveStandbyElector 创建成功,那么创建成功的 ActiveStandbyElector 对应的 NameNode 就会成为主 NameNode,ActiveStandbyElector 会回调 ZKFailoverController 的方法进一步将对应的 NameNode 切换为 Active 状态。而创建失败的 ActiveStandbyElector 对应的 NameNode 成为备 NameNode,ActiveStandbyElector 会回调 ZKFailoverController 的方法进一步将对应的 NameNode 切换为 Standby 状态。

数据复制(副本机制)

HDFS旨在可靠地在大型群集中的机器上存储文件。它将每个文件存储为一系列的块。文件的块被复制到多个节点(复制到几个由复制因子控制,hdfs-site.xml的dfs.replication属性)以实现容错。复制因子可以针对生成环境需要进行配置,复制因子可以在文件创建时指定,并可以稍后更改。
一个文件的所有块(文件越大按照块大小切分出来的块越多)中除最后一个块之外的所有块都具有相同的大小(hdfs-site.xml的dfs.blocksize)HDFS中的文件是一次写入的(附加和截断除外),并且在任何时候都严格限定只有一个writer。
**NameNode控制块的复制,它定期从集群中的每个DataNode接收Heartbeat和Blockreport。**收到Heartbeat意味着DataNode运行正常,Blockreport包含DataNode上所有块的列表(NameNode即可以知道是否有丢块或多块)。

副本放置策略

副本的放置对于HDFS的可靠性和性能至关重要。基于机架感知(Namenode知道副本在哪个rack)的副本放置策略的目的是提高数据可靠性,可用性和网络带宽利用率。
如果复制因子为3:
则HDFS的放置策略是在本地机器上放置第一个副本(如果写入器位于datanode上),否则随机放置在一个数据节点上;
第二个副本复制在另一个机架(非第一个副本所在的机架)的节点上;
第三个副本放在与第二个副本存放节点相同的机架上的其他节点上。
这样放置的优势所在:降低了读取数据时使用的总体网络带宽,因为块仅放置在两个独特的机架中,而不是三个。使用此策略,文件的副本不会均匀分布在机架上。三分之一的副本位于一个节点,三分之二的副本位于一个机架上,另外三分之一均匀分布在其余机架上。此策略可提高写入性能,而不会影响数据可靠性或读取性能。
注意:
如果复制因子大于3,则
随机确定第4个副本和后续副本的位置,同时将每个机架的副本数保持在上限以下((replicas - 1) / racks + 2)

由于NameNode不允许一个DataNode具有同一个块的多个副本,因此创建的最大副本数不应该大于DataNode节点的总数量。

副本选择(即读取的时候优先从哪个节点读取)

为了尽量减少全局带宽消耗和读取延迟,HDFS会尝试选择最接近读请求的块。如果在读节点的同一机架上存在副本,则该副本优先满足读取请求。如果HDFS群集跨越多个数据中心,则驻留在本地数据中心的副本优先于任何远程副本。

机架感知

在海量数据处理中,主要限制原因之一是节点之间数据的传输速率,即带宽。因此,将两个节点之间的带宽作为两个节点之间的距离的衡量标准。

hadoop为此采用了一个简单的方法:**把网络看作一棵树,两个节点之间的距离是他们到最近共同祖先的距离总和。**该树中的层次是没有预先设定的, 但是相对与数据中心,机架和正在运行的节点,通常可以设定等级。具体想法是针对以下每个常见,可用带宽依次递减:

  1. 同一节点上的进程;

  2. 同一机架上的不同节点;

  3. 同一数据中心中不同机架上的节点;

  4. 不同数据中心的节点

举个例子,假设有数据中心d1,机架r1中的节点n1。该节点可以表示为“/d1/r1/n1”。利用这种标记,这里给出四种距离描述:

  • 同一节点上的进程:/d1/r1/n1到/d1/r1/n1的距离
  • 同一机架上的不同节点: /d1/r1/n1到/d1/r1/n2的距离
  • 同一数据中心不同机架上的节点: /d1/r1/n1到/d1/r2/n2的距离
  • 不同数据中心上的节点: /d1/r1/n1到/d2/r2/n2的距离

注意点:

  1. 当没有配置机架信息时,**全部的机器Hadoop都默认在同一个默认的机架下,以名为”/default-rack”。**这样的情况下,不论什么一台datanode机器,无论物理上是否属于同一个机架。都会被觉得是在同一个机架下。

  2. 一旦配置topology.script.file.name。就依照网络拓扑结构来寻找datanode。topology.script.file.name这个配置选项的value指定为一个可运行程序。通常为一个脚本。
    官方的python脚本:

#!/usr/bin/python
# this script makes assumptions about the physical environment.
#  1) each rack is its own layer 3 network with a /24 subnet, which
# could be typical where each rack has its own
#     switch with uplinks to a central core router.
#
#             +-----------+
#             |core router|
#             +-----------+
#            /             \\
#   +-----------+        +-----------+
#   |rack switch|        |rack switch|
#   +-----------+        +-----------+
#   | data node |        | data node |
#   +-----------+        +-----------+
#   | data node |        | data node |
#   +-----------+        +-----------+
#
# 2) topology script gets list of IP's as input, calculates network address, and prints '/network_address/ip'.

import netaddr
import sys
sys.argv.pop(0)                                                  # discard name of topology script from argv list as we just want IP addresses

netmask = '255.255.255.0'                                        # set netmask to what's being used in your environment.  The example uses a /24

for ip in sys.argv:                                              # loop over list of datanode IP's
    address = '0/1'.format(ip, netmask)                      # format address string so it looks like 'ip/netmask' to make netaddr work
    try:
        network_address = netaddr.IPNetwork(address).network     # calculate and print network address
        print "/0".format(network_address)
    except:
        print "/rack-unknown"                                    # print catch-all value if unable to calculate network address

为什么需要HDFS?

当数据集的大小超出一台独立的服务服务器的存储能力时,应该怎么存储数据?答案就是对数据进行分区(partition)并将其存储到多个服务器上面,那这必然涉及到跨网络存储和管理,也势必引入网络编程的复杂性,因此,分布式的文件管理系统比普通的架设在单个服务器上的存储系统更加的复杂。Hadoop 生态圈中有一个组件叫做HDFS(Hadoop Distributed Filesystem) 就是专为了解决这个问题的分布式文件系统。

HDFS为什么要切块?

HDFS中对文件的存储是按照块进行的,文件进来后,它会将文件依据配置的大小进行切分为很多块(每个块的大小是可配置的比如,128M或64M等),然后对块进行存储。这样做有两个好处:

  1. 一个明显的好处是,一个文件的大小可以大于网络中任意一个磁盘的容量,文件的所有块并不需要存储在同一个磁盘上,因此它们可以利用集群上的任意一个磁盘进行存储。
  2. 另一个很重要的好处是,块很适合进行数据备份,从而提高了数据的容错能力和可用性。 HDFS默认会将块复制3个(默认值,可配置)单独的物理服务器上面进行容错。这样即使一个服务器挂了,也不会导致数据丢失,因为它会从另外的服务器进行读取并恢复成3个副本,同时也对负载进行均衡。

HDFS里面为什么一般设置块大小为64MB或128MB?

随着技术的发展你认为块的大小会有什么变化?

  1. 为什么不能远少于64MB?
    (1)减少硬盘寻道时间。 HDFS设计前提是应对大数据量操作,若数据块大小设置过小,那需要读取的数据块数量就会增多,从而间接增加底层硬盘的寻道时间,因为找到一个块,就需要寻道一次。
    (2) 减少NameNode内存消耗。 由于NameNode记录着DataNode中的数据块信息,若数据块大小设置过小,则数据块数量增多,需要维护的数据块信息就会增多,从而消耗NameNode的内存。现场出现过多次,因为存储了大量的小文件,导致NameNode内存溢出。对于HDFS来说,存储小文件是不合适的。

  2. 为什么不能远大于64MB?
    (1)问题分解问题。数据量的大小与问题解决的复杂度呈线性关系。对于同一个算法,处理的数据量越大,时间复杂度越高。
    (2)约束Map输出。在Map Reduce框架里,Map之后的数据是要经过排序才执行Reduce操作的。这通常涉及到归并排序,而归并排序的算法思想便是“对小文件进行排序,然后将小文件归并成大文件”,因此“小文件”不宜过大。
    (3)那么随着技术的发展,网络越来越快,磁盘也越来越快,内存,cpu性能越来越高,block的是可以增大的,我现在使用的block的大小就是128M,未来可能是256M也说不准。

HDFS的读写

HDFS写操作

(1) 客户端通过 Distributed FileSystem 模块向 NameNode 请求上传文件, NameNode 检查目标文件是否已存在,父目录是否存在。
(2) NameNode 返回是否可以上传。
(3) 客户端请求第一个 Block 上传到哪几个 DataNode 服务器上。
(4) NameNode 返回 3 个 DataNode 节点, 分别为 dn1、 dn2、 dn3。
(5) 客户端通过 FSDataOutputStream 模块请求 dn1 上传数据, dn1 收到请求会继续调用dn2,然后 dn2 调用 dn3,将这个通信管道建立完成。
(6) dn1、 dn2、 dn3 逐级应答客户端。
(7)客户端开始往 dn1 上传第一个 Block(先从磁盘读取数据放到一个本地内存缓存),以 Packet 为单位, dn1 收到一个 Packet 就会传给 dn2, dn2 传给 dn3; dn1 每传一个 packet会放入一个应答队列等待应答。
(8) 当一个 Block 传输完成之后,客户端再次请求 NameNode 上传第二个 Block 的服务器。(重复执行 3-7 步)。

HDFS读操作

(1) 客户端通过 DistributedFileSystem 向 NameNode 请求下载文件, NameNode 通过查询元数据,找到文件块所在的 DataNode 地址。
(2) 挑选一台 DataNode(就近原则,然后随机)服务器,请求读取数据。
(3) DataNode 开始传输数据给客户端(从磁盘里面读取数据输入流,以 Packet 为单位来做校验)。
(4) 客户端以 Packet 为单位接收,先在本地缓存,然后写入目标文件。

SecondaryNameNode

引用:https://blog.csdn.net/xh16319/article/details/31375197

fsimage和edit logs

NameNode主要是用来保存HDFS的元数据信息,比如命名空间信息,块信息等。当它运行的时候,这些信息是存在内存中的。但是这些信息也可以持久化到磁盘上。

Fsimage文件: HDFS文件系统元数据的一个永久性的检查点,其中包含HDFS文件系统的所有目录和文件inode的序列化信息。
Fsimage部分内容如下:

<inode>
	<id>16386</id>
	<type>DIRECTORY</type>
	<name>user</name>
	<mtime>1512722284477</mtime>
	<permission>atguigu:supergroup:rwxr-xr-x</permission>
	<nsquota>-1</nsquota>
	<dsquota>-1</dsquota>
</inode>
<inode>
	<id>16387</id>
	<type>DIRECTORY</type>
	<name>atguigu</name>
	<mtime>1512790549080</mtime>
	<permission>atguigu:supergroup:rwxr-xr-x</permission>
	<nsquota>-1</nsquota>
	<dsquota>-1</dsquota>
</inode>
<inode>
	<id>16389</id>
	<type>FILE</type>
	<name>wc.input</name>
	<replication>3</replication>
	<mtime>1512722322219</mtime>
	<atime>1512722321610</atime>
	<perferredBlockSize>134217728</perferredBlockSize>
	<permission>atguigu:supergroup:rw-r--r--</permission>
	<blocks>
		<block>
		<id>1073741825</id>
		<genstamp>1001</genstamp>
		<numBytes>59</numBytes>
		</block>
	</blocks>
</inode >

Fsimage 中没有记录块所对应 DataNode,为什么?
在集群启动后,要求 DataNode 上报数据块信息,并间隔一段时间后再次上报。

Edit logs: 存放HDFS文件系统的所有更新操作的路径, 文件系统客户端执行的所有写操作首先会被记录到Edits文件中。

<?xml version="1.0" encoding="UTF-8"?>
<EDITS>
<EDITS_VERSION>-63</EDITS_VERSION>
<RECORD>
<OPCODE>OP_START_LOG_SEGMENT</OPCODE>
<DATA>
<TXID>129</TXID>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_ADD</OPCODE>
<DATA>
<TXID>130</TXID>
<LENGTH>0</LENGTH>
<INODEID>16407</INODEID>
<PATH>/hello7.txt</PATH>
<REPLICATION>2</REPLICATION>
<MTIME>1512943607866</MTIME>
<ATIME>1512943607866</ATIME>
<BLOCKSIZE>134217728</BLOCKSIZE>
<CLIENT_NAME>DFSClient_NONMAPREDUCE_-
1544295051_1</CLIENT_NAME>
<CLIENT_MACHINE>192.168.10.102</CLIENT_MACHINE>
<OVERWRITE>true</OVERWRITE>
<PERMISSION_STATUS>
<USERNAME>atguigu</USERNAME>
<GROUPNAME>supergroup</GROUPNAME>
<MODE>420</MODE>
</PERMISSION_STATUS>
...
...

SecondaryNameNode机制

**只有在NameNode重启时,edit logs才会合并到fsimage文件中,从而得到一个文件系统的最新快照。**但是在产品集群中NameNode是很少重启的,**这也意味着当NameNode运行了很长时间后,edit logs文件会变得很大。**在这种情况下就会出现下面一些问题:

  1. edit logs文件会变的很大,怎么去管理这个文件是一个挑战。
  2. NameNode的重启会花费很长时间,因为有很多改动[笔者注:在edit logs中]要合并到fsimage文件上。
  3. 如果NameNode挂掉了,那我们就丢失了很多改动因为此时的fsimage文件非常旧。[笔者注: 笔者认为在这个情况下丢失的改动不会很多, 因为丢失的改动应该是还在内存中但是没有写到edit logs的这部分。]

因此为了克服这个问题,我们需要一个易于管理的机制来帮助我们减小edit logs文件的大小和得到一个最新的fsimage文件,这样也会减小在NameNode上的压力。这跟Windows的恢复点是非常像的,Windows的恢复点机制允许我们对OS进行快照,这样当系统发生问题时,我们能够回滚到最新的一次恢复点上。

SecondaryNameNode就是来帮助解决上述问题的,它的职责是合并NameNode的edit logs到fsimage文件中。
SecondaryNameNode有两个作用,一是镜像备份,二是日志与镜像的定期合并。两个过程同时进行,称为checkpoint. 镜像备份的作用:备份fsimage(fsimage是元数据发送检查点时写入文件);日志与镜像的定期合并的作用:将Namenode中edits日志和fsimage合并,防止(如果Namenode节点故障,namenode下次启动的时候,会把fsimage加载到内存中,应用edit log,edit log往往很大,导致操作往往很耗时。)
Secondarynamenode工作原理:
上面的图片展示了Secondary NameNode是怎么工作的。

  1. SecondaryNameNode通知NameNode准备提交edits文件,此时主节点产生edits.new
  2. SecondaryNameNode通过http get方式获取NameNode的fsimage与edits文件(在SecondaryNameNode的current同级目录下可见到 temp.check-point或者previous-checkpoint目录,这些目录中存储着从namenode拷贝来的镜像文件)
  3. SecondaryNameNode开始合并获取的上述两个文件,产生一个新的fsimage文件fsimage.ckpt
  4. SecondaryNameNode用http post方式发送fsimage.ckpt至NameNode
  5. NameNode将fsimage.ckpt与edits.new文件分别重命名为fsimage与edits,然后更新fstime,整个checkpoint过程到此结束。 在新版本的hadoop中,SecondaryNameNode两个作用被两个节点替换, checkpoint node与backup node. SecondaryNameNode备份由三个参数控制fs.checkpoint.period控制周期,fs.checkpoint.size控制日志文件超过多少大小时合并, dfs.http.address表示http地址,这个参数在SecondaryNameNode为单独节点时需要设置。 Secondary NameNode的整个目的是在HDFS中提供一个检查点。它只是NameNode的一个助手节点。这也是它在社区内被认为是检查点节点的原因。
    现在,我们明白了Secondary NameNode所做的不过是在文件系统中设置一个检查点来帮助NameNode更好的工作。它不是要取代掉NameNode也不是NameNode的备份。所以从现在起,让我们养成一个习惯,称呼它为检查点节点吧。

HDFS负载均衡

Hadoop的HDFS集群非常容易出现机器与机器之间磁盘利用率不平衡的情况,例如:当集群内新增、删除节点,或者某个节点机器内硬盘存储达到饱和值。当数据不平衡时,Map任务可能会分配到没有存储数据的机器,这将导致网络带宽的消耗,也无法很好的进行本地计算。

当HDFS负载不均衡时,需要对HDFS进行数据的负载均衡调整,即对各节点机器上数据的存储分布进行调整。从而,让数据均匀的分布在各个DataNode上,均衡IO性能,防止热点的发生。进行数据的负载均衡调整,必须要满足如下原则:

  • 数据平衡不能导致数据块减少,数据块备份丢失
  • 管理员可以中止数据平衡进程
  • 每次移动的数据量以及占用的网络资源,必须是可控的
  • 数据均衡过程,不能影响namenode的正常工作

HDFS数据负载均衡原理

数据均衡过程的核心是一个数据均衡算法**,该数据均衡算法将不断迭代数据均衡逻辑,使得数据较多的节点上面的数据向数据较少的节点移动,直至集群内数据均衡为止。**该数据均衡算法每次迭代的逻辑如下:
步骤分析如下:

  1. **数据均衡服务(Rebalancing Server)**首先要求 NameNode 生成 DataNode 数据分布分析报告,获取每个DataNode磁盘使用情况
  2. Rebalancing Server汇总需要移动的数据分布情况,计算具体数据块迁移路线图。数据块迁移路线图,确保网络内最短路径
  3. 开始数据块迁移任务,Proxy Source Data Node复制一块需要移动数据块将复制的数据块复制到目标DataNode上
  4. 删除原始数据块
  5. 目标DataNode向Proxy Source Data Node确认该数据块迁移完成
  6. Proxy Source Data Node向Rebalancing Server确认本次数据块迁移完成。然后继续执行这个过程,直至集群达到数据均衡标准

HDFS快照

Hdfs的快照(snapshot)是在某一时间点对指定文件系统拷贝,快照采用只读模式,可以对重要数据进行恢复、防止用户错误性的操作。 快照分两种,Hdfs属于前者

  • 建立文件系统的索引,每次更新文件不会真正的改变文件,而是新开辟一个空间用来保存更改的文件;
  • 拷贝所有的文件系统

HDFS数据完整性

受网络不稳定、硬件损坏等因素,IO操作过程中难免会出现数据丢失或脏数据,难免会出现数据丢失或脏数据,数据传输的量越大,出现错误的概率就越高。
检测数据是否损坏的常见措施是,**在数据第一次引入系统时计算校验和(checksum)并存储,在数据进行传输后再次计算校验和进行对比,如果计算所得的新校验和和原来的校验和不匹配,就认为数据已损坏。**注意,校验和也是可能损坏的,因为校验和本身也是数据,但由于校验和比数据小得多,所以损坏的概率比较小。

对本地文件I/O的检查

在Hadoop中,本地文件系统的数据完整性由客户端负责。重点在读取文件时进行校验和的处理。
每当hadoop创建文件file时,hadoop就会同时在同一个文件夹下创建隐藏文件.file.crc,这个文件记录了 文件a的校验和。

对HDFS的I/O数据进行检查
一般来说,HDFS会在三种情况下检验校验和

  1. DataNode接收数据后存储数据前 DataNode接收数据一般有两种情况:
  • 从客户端上传数据
  • DataNode从其他DataNode上接收数据。
    当客户端上传数据时,正在写数据的客户端将数据及其校验和发送到由一系列datanode组成的Pipeline管线Pipeline管线中最后一个datanode负责验证校验和
  1. 客户端读取DataNode上的数据时 Hadoop会在客户端读取DataNode上的数据时,使用DFSClient中的read函数先将数据读入到用户的数据缓冲区,然后再检查校验和。


将他们与datanode中存储的校验和进行比较,每个datanode均持久保存有一个用于验证的校验和日志,所以它知道每个数据块的最后一次验证时间,客户端成功验证一个数据块后,会告诉这个datanode,datanode由此更新日志。

  • DataNode后台守护进程的定期检查 DataNode会在后台运行DataBlockScanner这个程序定期(hdfs-site.xml)验证存储在这个datanode上的所有数据块(3周) 。该项措施是解决物理存储媒体上位衰减,位损坏的有力措施。

Hadoop处理损坏数据的机制

  1. DataNode在读取block块的时候会先进行checksum(数据块校验和),如果client发现本次计算的校验和跟创建时的校验和不一致,则认为该block块已损坏
  2. 客户端在抛出ChecksumException之前上报该block信息给namenode进行标记(“已损坏”),这样namenode就不会把客户端指向这个block,也不会复制这个block到其他的datanode。
  3. client重新读取另外的datanode上的block
  4. 在心跳返回时NameNode将块的复制任务交给DataNode,从完好的block副本进行复制以达到默认的备份数3
  5. NameNode删除掉坏的block
  6. DataNode在一个block块被创建之日起三周后开始进行校验

以上是关于HDFS深入学习总结的主要内容,如果未能解决你的问题,请参考以下文章

HadoopHadoop 机架感知配置原理

hadoop之 hadoop 机架感知

HDFS纠删码技术介绍

HDFS学习:HDFS机架感知与副本放置策略

[HDFS_add_3] HDFS 机架感知

HDFS机架感知