在Hadoop读数据的过程中,会从与Client端最这距离的datanode的block副本去读数据,那这个距离怎么计算?策略是与Client同一个datanode结点的优先权最高,其次是本机架结点,否则随机。我们知道在读数据的时候Client首先会与namenode打交道,向namenode发送RPC请求获取block及对应的datanode位置列表,由Namenode端计算距离后按距离由近及远,返回位置列表。
NameNode类:
public LocatedBlocks getBlockLocations(String src,
long offset,
long length) throws IOException {
myMetrics.numGetBlockLocations.inc();
return namesystem.getBlockLocations(getClientMachine(),
src, offset, length);
}
FSNamesystem类
/**
* Get block locations within the specified range.
*
* @see #getBlockLocations(String, long, long)
*/
LocatedBlocks getBlockLocations(String clientMachine, String src,
long offset, long length) throws IOException {
if (isPermissionEnabled) {
checkPathAccess(src, FsAction.READ);
}
LocatedBlocks blocks = getBlockLocations(src, offset, length, true);
if (blocks != null) {
//sort the blocks
DatanodeDescriptor client = host2DataNodeMap.getDatanodeByHost(
clientMachine);
for (LocatedBlock b : blocks.getLocatedBlocks()) {
clusterMap.pseudoSortByDistance(client, b.getLocations());
//调用的是NetworkTopology类的pseudoSortByDistance方法计算client与datanode的距离方法
}
}
return blocks;
}
NetworkTopology类
计算距离的核心部分
public void pseudoSortByDistance( Node reader, Node[] nodes ) {
int tempIndex = 0;
if (reader != null ) {
int localRackNode = -1;
//scan the array to find the local node & local rack node
for(int i=0; i<nodes.length; i++) { //分别通过tempIndex和localRackNode标识是否找到本地结点和本机架结点,两类都找到则退出循环
if(tempIndex == 0 && reader == nodes[i]) { //local node
//发现本地结点
//swap the local node and the node at position 0
if( i != 0 ) {
swap(nodes, tempIndex, i); //找到本地结点并且不在列表的第一个位置,与第一个位置交换
}
tempIndex=1;
if(localRackNode != -1 ) { //在找到本地的时候如果发生已经有了本架,并且本架在第一个位置,将本架的标量指定到本地的位置(因为前面已经把本地的与第一个位置交换了)
if(localRackNode == 0) {
localRackNode = i;
}
break;
}
}
else if(localRackNode == -1 && isOnSameRack(reader, nodes[i])) {
//发现本机架结点
//local rack
localRackNode = i;
if(tempIndex != 0 ) break;
}
}
// swap the local rack node and the node at position tempIndex,
//把本架结点放第一个位,或第二位,如果有本架结点,跟tempIndex交换,tempIndex要么为0,要么为1,分别交换没本地结点,有本地结点的情况
//没有本地,本架则放第一位,有本地,本架放第二位,swap tempIndex就做到了
if(localRackNode != -1 && localRackNode != tempIndex ) {
swap(nodes, tempIndex, localRackNode);
tempIndex++;
}
}
// put a random node at position 0 if it is not a local/local-rack node
//随机取结点放置在第一个位置,此语句没有本地和本架才发生,感觉这个没有多少意义
if(tempIndex == 0 && nodes.length != 0) {
swap(nodes, 0, r.nextInt(nodes.length));
}
}
}