FSNamesystem.ReplicationMonitor线程负责对block进行复制。run方法不断循环执行computeDatanodeWork()方法,对blokc进行复制和失效操作。computeReplicationWork()方法会遍历所有需要复制的block,调用computeReplicationWorkForBlock()进行复制操作。
该方法调用BlockPlacementPolicyDefault放置策略对象的chooseTarget()来选择复制的所有目标节点。会先将CPU不忙和磁盘不满的节点
DatanodeDescriptor targets[] = replicator.chooseTarget(fileINode,
requiredReplication - numEffectiveReplicas,
srcNode, containingNodes, block.getNumBytes());
默认实现类BlockPlacementPolicyDefault采用策略:
1、第一个副本:放置在CPU不忙,磁盘不满的节点。会通过isGoodTarget过滤无法存放block的节点。
2、第二个副本:选择一个远程机架(和当前节点不同机架)上的随机节点存放。
3、第三个副本:如果前两个节点不再同一个机架,选择和第二个副本相同机架的随机不同节点。如果前两个节点在同一个机架,再选择一个RemoteRack远程机架的节点。(越近越快)
4、超出三个的其余副本,随机选择节点,chooseRandom()。
try {
if (numOfResults == 0) {
writer = chooseLocalNode(writer, excludedNodes, blocksize,
maxNodesPerRack, results, avoidStaleNodes);
if (--numOfReplicas == 0) {
return writer;
}
}
if (numOfResults <= 1) {
chooseRemoteRack(1, results.get(0), excludedNodes, blocksize,
maxNodesPerRack, results, avoidStaleNodes);
if (--numOfReplicas == 0) {
return writer;
}
}
if (numOfResults <= 2) {
if (clusterMap.isOnSameRack(results.get(0), results.get(1))) {
chooseRemoteRack(1, results.get(0), excludedNodes, blocksize,
maxNodesPerRack, results, avoidStaleNodes);
} else if (newBlock){
chooseLocalRack(results.get(1), excludedNodes, blocksize,
maxNodesPerRack, results, avoidStaleNodes);
} else {
chooseLocalRack(writer, excludedNodes, blocksize, maxNodesPerRack,
results, avoidStaleNodes);
}
if (--numOfReplicas == 0) {
return writer;
}
}
chooseRandom(numOfReplicas, NodeBase.ROOT, excludedNodes, blocksize,
maxNodesPerRack, results, avoidStaleNodes);