HDFS维持副本平衡的流程
HDFS上文件的block默认会存放3个副本,一个副本存在一个rack的某个dn上,第二个和第三个副本存放在另一个机架的某两个dn上,nn会维持block的副本平衡,但是当集群上的副本数超过3个时,nn会删除那些节点上的副本来维护副本平衡呢?当集群上的副本数少于3个时,会原则那些节点作为原点进行复制呢?那就查下代码看nn是怎么搞的
HDFS删除多余副本
多余副本的场景
- rack0上有一个副本,rack1上有两个副本,此时rack0的dn下线,nn维持副本平衡,复制一个副本到其它的rack上,3副本平衡,但是下线的dn又重新上线了,这就出现了4个副本,需要删除一个副本
- 调用
hadoop fs -setrep -R 3
相关命令人为修改副本的个数,
删除多余副本
BlockManager主要管理block存储在集群中的相关信息,查看其processOverReplicatedBlock
方法,处理多余副本,
1 | /** |
processOverReplicatedBlock将block的副本所在的节点放在nonExcess集合中,然后调用chooseExcessReplicates
1 | /** |
chooseExcessReplicates的处理逻辑是,调用replicator.splitNodesWithRack
将nonExcess分为两个集合,然后循环的调用replicator.chooseReplicaToDelete
选出要删除副本的节点,放入excessReplicateMap和invalidateBlocks中,等待delete掉。
moreThanOne和exactlyOne的划分规则在splitNodesWithRack
中,代码如下:
1 | public void splitNodesWithRack( |
splitNodesWithRack划分结束之后,在chooseExcessReplicates中进行while循环来删除多余的副本,直到达到期望副本个数。
删除节点的选择是在chooseReplicaToDelete
中决定的,该方法在BlockPlacementPolicyDefault中被重写。选取规则为
- 如果moreThanOne不是empty,则先把moreThanOne做为节点集合
- 首先选择心跳时间间隔最长的节点或者
- 如果所有的心跳都在允许的间隔之内,则选择剩余空间最少的节点,
1 | // BlockPlacementPolicyDefault.class |
选出要删除的节点cur之后,调用adjustSetsWithChosenReplica
重新调整rackMap、moreThanOne和exactlyOne,并调用addToExcessReplicate
将cur放入excessReplicateMap中
1 | private void addToExcessReplicate(DatanodeInfo dn, Block block) { |
最后会将cur放入invalidateBlocks中,随后cur会被删除
1 | void addToInvalidates(final Block block, final DatanodeInfo datanode) { |
invalidateBlocks在哪被删除(在ReplicationMonitor的中)
HDFS修复缺少副本
当HDFS上某个block的副本数低于期望的副本数时,会调用processMisReplicatedBlock
进行处理
1 | /** |
processMisReplicatedBlock根据该block的信息,将block打上标签并放入不同的队列中进行处理。利用countNodes
计算其副本数
1 | /** |
processMisReplicatedBlock中用isNeededReplication判断是否需要进行增加副本数,current < expected || !blockHasEnoughRacks(b)
为true时,则调用neededReplications.add
进行增加副本,neededReplications是UnderReplicatedBlocks的实例,UnderReplicatedBlocks是HDFS中关于块复制的一个重要数据结构。add方法如下:
1 | synchronized boolean add(Block block, |
add将根据block相关副本的优先级放入under replication queue中,优先级从getPriority
中获取,级别有5中,从0开始,0的优先级最高,则4最低。
- QUEUE_HIGHEST_PRIORITY = 0
最高优先级,主要针对数据块副本数非常的、严重的不足的情况,当前副本数低于期望值,且仅有1个或者干脆没有,比如副本数仅有1个,或者副本数干脆为0,但是还存在退役副本,这种情况最危险,数据最容易丢失,所以复制的优先级也最高 - QUEUE_VERY_UNDER_REPLICATED = 1
主要针对数据块副本数不足但没有上面严重的情况,如当前副本数低于期望值,但是副本数大于1,其判断公式为当前副本数curReplicas乘以3还小于期望副本数expectedReplicas,这种情况也比较危险,数据也容易丢失,所以复制的优先级也很高 - QUEUE_UNDER_REPLICATED = 2
主要针对数据块副本数低于期望值,但是还不是很严重,也可以理解为正常缺失副本块 - QUEUE_REPLICAS_BADLY_DISTRIBUTED = 3
有足够(大于或者等于正确的副本数)的副本个数,但是并不符合副本的放置策略,副本分布不均衡 - QUEUE_WITH_CORRUPT_BLOCKS = 4
主要针对损坏的数据块的情况,其副本数位0,但是还没有退役副本
1 | private int getPriority(Block block, |
通过getPriority得到优先级之后,从priorityQueues list中拿到相同优先级的LightWeightLinkedSet set,将block放入set中。最后在processMisReplicatedBlock
方法中返回该block的标记MisReplicationResult.UNDER_REPLICATED
通过上面的代码nn将缺少副本的block根据复制优先级放入不同的queue中,等待复制线程进行复制。
附加:副本默认放置策略
默认的放置策略大家都熟悉,3副本分布在两个rack上,一个rack上有一个副本,另一个rack上有两个副本,这里就只简单的列出代码的部分实现,代码入口是BlockPlacementPolicyDefault.chooseTarget,这里只列主要的逻辑代码chooseTarget:
1 | private Node chooseTarget(int numOfReplicas, |