NetworkTopology 是common 包下的一个类,用来描述hadoop 集群的节点网络拓扑。在HDFS 中,这个类会在选DN 的场景下被使用。NetworkTopology将整个集群中的DN存储成了一个树状网络拓扑图, 表示一个具有树状网络拓扑结构的计算机集群, 一个集群可能由多个数据中心Data Center组成, 在这些数据中心分布着为计算需求而设置的很多计算机的机架Rack. InnerNode内部类, 表示数据中心/机架的转换器/或路由
通常来说,一个DN 的拓扑一般是这样的结构 /region/az/idc/room/tor/rack/x,region 通常表示一个地区,az 是逻辑机房,包含多个idc,在idc 内部,通常包含多个房间,每个房间有不同的机柜,一个机柜包含很多机架,而DN (可以抽象为物理机)就放置在机架上。
Node 接口定义了在网络拓扑中的每一个节点。每一个Node 在网络拓扑中应该有一个名称及其位置(使用类似文件路径的方式来定义), 例如一个Datanode名称为hostname:port, 并且该Datanode在数据中心dog里的orange机架上, 则这个Datanode在网络拓扑中的位置(网络地址)为/dog/orange.
NodeBase 实现了Node接口, 是一个最基本的结点的实现. 该类定义的属性都是与一个结点的基本属性信息相关的。假设DN节点的路径path=/a/b/c, 则节点名称name=c, 节点路径location=/a/b. 节点的 path 不需要定义, 由 location/name组成。按照NodeBase的实现, 子节点的location=父节点的path。
下面来看InnerNode.getLoc()
假设传入的loc=/a/b/c 表示在region=a,az=b,idc=c,这个方法需要从/a/b/c 这个idc 内选一个节点,当然,这个Node 同样是个树状结构。首先 /a/b/c normalize 后变成a/b/c
- /** Given a string representation of a node, return its reference
- *
- * @param loc
- * a path-like string representation of a node
- * @return a reference to the node; null if the node is not in the tree
- */
- public Node getNode(String loc) {
- netlock.readLock().lock();
- try {
- loc = NodeBase.normalize(loc);
- if (!NodeBase.ROOT.equals(loc))
- loc = loc.substring(1);
- return clusterMap.getLoc(loc);
- } finally {
- netlock.readLock().unlock();
- }
- }
- /** Given a node's string representation, return a reference to the node 参数loc说明了不会传递dn节点名称进来 */
- private Node getLoc(String loc) {
- if (loc == null || loc.length() == 0) return this;
-
- String[] path = loc.split(PATH_SEPARATOR_STR, 2); // 如果loc=r1/r2, path=[r1, r2]; 如果loc=r1/r2/r3, path=[r1, r2/r3]
- Node childnode = null;
- for(int i=0; i
- if (children.get(i).getName().equals(path[0])) {
- childnode = children.get(i);
- }
- }
- if (childnode == null) return null; // non-existing node
- if (path.length == 1) return childnode;
- if (childnode instanceof InnerNode) {
- return ((InnerNode)childnode).getLoc(path[1]); // 递归调用
- } else {
- return null;
- }
- }
第一次 path[0]=region=a 找到/ 下所有的子节点(假设只有/a)匹配上之后,childnode = /a,然后递归 /a .getLoc(b/d)
第二次 path[0]=az=b 找到/a 下所有子节点(假设只有/a/b)匹配上之后,childnode = /a/b 然后递归 /a/b. getLoc(d)
第三次 path[0]=idc=d 找到/a/b 下所有子节点(假设只有/a/b/d)匹配上之后,childnode = /a/b/d 此时path 长度=1,返回 childnode。
这个返回值最后会作为chooseRandom 的入参,在这个节点下的所有节点中选一个DN 出来。