上一文,我们讲了nn在内存中如何对元数据进行存储和管理的,文章最后也提到了nn内部如何保证块的副本数维持在指定个数,即对副本缺失的块触发块副本复制,对副本多余的块触发块副本删除。本文就来详细聊聊具体流程及细节。
【块副本复制的场景与处理逻辑】
哪些时候会出现需要块的副本数不够,需要进行块副本复制呢?
一种是客户端或管理员手动修改块的副本数,将其扩大;另一种则是块副本所在dn节点异常,包括网络异常,物理机异常,程序被kill导致的异常下线;又或者是块副本存储所在dn节点的磁盘异常,例如磁盘被拔掉,或者确实出现了坏盘。两种情况都会导致块的副本数不满足实际设置要求。
不管哪种情况,在nn内部最终处理时(处理dn的块汇报、处理dn的心跳超时,处理管理员或客户端的设置),都会将不满足副本数的块放到UnderReplicatedBlocks中。
接下来就是块副本复制的处理流程(看图说话)
1. 块副本监测线程(ReplicationMonitorThread)定时监测是否有不满足副本数的块,如果有则取出块信息。
2. 根据块的当前副本数情况,选择一个作为副本复制源的dn节点,同时结合块的存储要求,选择一个合适dn节点,作为复制的目的节点。
3. 然后封装成一个任务放到复制源dn节点信息(DatanodeDescriptor)的链表中。
4. 同时将块副本复制任务进行封装放到等待执行块副本复制的队列中。
5. 此后,nn在处理块副本复制源的dn节点的心跳处理时,从队列中取出块副本复制任务作为心跳响应的命令下发给dn,dn节点处理心跳响应的命令,向指定的节点建立连接并传输块副本数据及校验和数据。
当dn完成块副本的数据传输后,目的端的dn节点会通过增量块汇报向dn上报块副本的信息。
6. 在块副本监测线程将块副本复制任务放到队列后,另外一个等待块副本复制的监测线程(PendingReplicationMonitorThread)定时监测块副本复制队列中任务情况,如果块副本复制任务在队列中超过指定时间,其块的副本数仍旧没有达到指定副本数时,将该任务从队列取出置为超时状态,并将其放到超时队列中。如果已经达到指定副本数,则直接从队列中移除。
7. 上面提到的块副本监测线程在一轮处理的最后,会将超时队列中的任务重新加到UnderReplicatedBlocks中,等待下次轮询时再重复上面的处理逻辑。
【处理中的一些细节】
首先是用于存储块副本数的不满足的UnderReplicatedBlocks采用了5个队列,每个队列中又是一个轻量级的集合的方式进行存储。
5个队列实际上对应5个不同的优先级,即对不满足副本数的块定义了不同的优先级,这些块在存储时按按优先级存到不同的队列中,取出时则按高优先级到低优先级的顺序依次取出触发块副本复制任务。
对应源码:
其次,在块副本复制的过程中,是具有一定的流控机制的。具体体现为:
块副本监测线程的执行是有一定时间间隔的
块副本监测线程每次从UnderReplicationBlocks中取出的块个数是有限制的,每次轮询触发块副本的个数为:当前在线的dn节点数 ✖️ 指定系数
nn通过心跳给dn下发块副本复制任务也是有最大限制的,即如果给某个dn下发的块副本复制任务已经达到最大数,在该dn(任意一个块副本复制任务)未完成之前,不会再继续下发复制任务。
这样一来,可以确保dn节点不会瞬间因大量的副本复制任务影响到正常的读写流程。
【块副本删除的流程】
既然有不满足副本数的场景,那么相应的也会有超过副本数的场景,例如客户端或管理员对某个文件设置比原来小的副本数;或者某个dn节点异常先触发了副本复制任务,在完成副本复制之后,异常的节点又恢复了,这个时候节点重新向nn注册并进行块汇报,就出现了某些块的副本数超出了指定个数的情况。
块副本删除的处理逻辑和块副本复制的处理流程几乎相同,首先是超出副本数的块会存放到指定的地方(InvalidBlocks);其次,同样是在副本监测线程中从invalidBlocks中取出块的信息,并决定需要从哪个dn节点删除对应的块副本,构造对应的删除任务放到dn节点信息的某个链表中,然后在心跳响应中将任务下发给dn节点。
最后,块副本的删除也同样是具有一定流控机制的。
相关配置整理:
# 副本监测线程轮询处理的时间间隔
# 默认时间间隔为3s
dfs.namenode.replication.interval
# 每次触发副本复制的系数
# 默认为2, 即当前在线dn节点数的2倍
dfs.namenode.replication.work.multiplier.per.iteration
# 单个dn的最大副本复制任务数
# 默认值为2个
dfs.namenode.replication.max-streams
# 每次触发副本删除的系数
# 默认为0.32
dfs.namenode.invalidate.work.pct.per.iteration
# 单个dn副本删除任务的上限
dfs.block.invalidate.limit
【总结】
本文主要讲解了nn中块副本复制、块副本删除的流程,由此可以看出,hdfs具备一套完整的机制来确保副本数与设置的数目保持一致。
里面还可以深究的一些点,例如块副本复制时,如何选择源节点,目的节点的选择会受哪些因素制约;同样,块副本删除时怎么选择应当删除哪个节点上的副本;块副本的复制会产生额外的带宽,是否会影响正常的写等等,我们下次再聊~
好了,本文就介绍到这里,如果觉得本文对你有些帮助,来个点赞,在看吧,也欢迎分享转发, 谢谢~