NameNode中数据节点的保存(1)——Host2NodesMap

来源:互联网 发布:网络协议的四层模型 编辑:程序博客网 时间:2024/04/30 16:38

对于一台主机,我们可以在它上面部署多个DataNode进程,这也就是说在一台机器上有多个DataNode节点,而且这些DataNode节点属于同一个HDFS集群,那么这里就有一个问题了,NameNode节点是如何考虑整个集群的负载均衡的?如果NameNode节点以DataNode节点为单位来考虑负载均衡的话,就会出现包含有多个DataNode节点的主机负载过重,所以就不得不以主机为单位来计算集群的负载情况了。在NameNode中用Host2NodesMap类来存储主机与DataNode节点之间的映射。

     当一个DataNode节点向NameNode注册成功的时候,NameNode就会把这个DataNode节点存储到它的host2DataNodeMap属性中,也就是Host2NodesMap类的一个实例,这个类主要包含三个属性:

map:存储集群中所有主机上的所有DataNode节点;

r:用来随机选择给定主机上的某一个DataNode节点;

hostmapLock:控制对map的同步操作;

     Host2NodesMap类主要负责对集群中的DataNode节点按在它们所在的主机进行分类管理,它可用来添加、删除、查询一个DataNode节点,它也可以按照主机或者DataNode的名字来查询。这些操作对应的方法是:

  1. //判断一个DataNode节点在不在集群中  
  2.   
  3. boolean contains(DatanodeDescriptor node) {  
  4.     if (node==null) {  
  5.       return false;  
  6.     }  
  7.         
  8.     String host = node.getHost();  
  9.     hostmapLock.readLock().lock();  
  10.     try {  
  11.       DatanodeDescriptor[] nodes = map.get(host);  
  12.       if (nodes != null) {  
  13.         for(DatanodeDescriptor containedNode:nodes) {  
  14.           if (node==containedNode) {  
  15.             return true;  
  16.           }  
  17.         }  
  18.       }  
  19.     } finally {  
  20.       hostmapLock.readLock().unlock();  
  21.     }  
  22.       
  23.     return false;  
  24.   }  
  25.       
  26.   //添加一个数据节点  
  27.   boolean add(DatanodeDescriptor node) {  
  28.     hostmapLock.writeLock().lock();  
  29.     try {  
  30.       if (node==null || contains(node)) {  
  31.         return false;  
  32.       }  
  33.       //找到DataNode节点所在的host  
  34.   
  35.       String host = node.getHost();  
  36.       DatanodeDescriptor[] nodes = map.get(host);  
  37.       DatanodeDescriptor[] newNodes;  
  38.       if (nodes==null) {  
  39.         newNodes = new DatanodeDescriptor[1];  
  40.         newNodes[0]=node;  
  41.       } else { // rare case: more than one datanode on the host  
  42.         newNodes = new DatanodeDescriptor[nodes.length+1];  
  43.         System.arraycopy(nodes, 0, newNodes, 0, nodes.length);  
  44.         newNodes[nodes.length] = node;  
  45.       }  
  46.       map.put(host, newNodes);  
  47.       return true;  
  48.     } finally {  
  49.       hostmapLock.writeLock().unlock();  
  50.     }  
  51.   }  
  52.       
  53.   //删除一个节点  
  54.   boolean remove(DatanodeDescriptor node) {  
  55.     if (node==null) {  
  56.       return false;  
  57.     }  
  58.         
  59.     String host = node.getHost();  
  60.     hostmapLock.writeLock().lock();  
  61.     try {  
  62.       DatanodeDescriptor[] nodes = map.get(host);  
  63.       if (nodes==null) {  
  64.         return false;  
  65.       }  
  66.       if (nodes.length==1) {  
  67.         if (nodes[0]==node) {  
  68.           map.remove(host);  
  69.           return true;  
  70.         } else {  
  71.           return false;  
  72.         }  
  73.       }  
  74.       //rare case  
  75.       int i=0;  
  76.       for(; i<nodes.length; i++) {  
  77.         if (nodes[i]==node) {  
  78.           break;  
  79.         }  
  80.       }  
  81.       if (i==nodes.length) {  
  82.         return false;  
  83.       } else {  
  84.         DatanodeDescriptor[] newNodes;  
  85.         newNodes = new DatanodeDescriptor[nodes.length-1];  
  86.         System.arraycopy(nodes, 0, newNodes, 0, i);  
  87.         System.arraycopy(nodes, i+1, newNodes, i, nodes.length-i-1);  
  88.         map.put(host, newNodes);  
  89.         return true;  
  90.       }  
  91.     } finally {  
  92.       hostmapLock.writeLock().unlock();  
  93.     }  
  94.   }  
  95.       
  96.   //根据主机名获取这个主机上的一个DataNode节点,如果这个主机上有多个DataNode节点,则随机选一个  
  97.   DatanodeDescriptor getDatanodeByHost(String host) {  
  98.     if (host==null) {  
  99.       return null;  
  100.     }  
  101.         
  102.     hostmapLock.readLock().lock();  
  103.     try {  
  104.       DatanodeDescriptor[] nodes = map.get(host);  
  105.       // no entry  
  106.       if (nodes== null) {  
  107.         return null;  
  108.       }  
  109.       // one node  
  110.       if (nodes.length == 1) {  
  111.         return nodes[0];  
  112.       }  
  113.       // more than one node  
  114.       return nodes[r.nextInt(nodes.length)];  
  115.     } finally {  
  116.       hostmapLock.readLock().unlock();  
  117.     }  
  118.   }  
  119.       
  120.   //根据DataNode节点的名字来找到这个节点  
  121.   public DatanodeDescriptor getDatanodeByName(String name) {  
  122.     if (name==null) {  
  123.       return null;  
  124.     }  
  125.         
  126.     int colon = name.indexOf(":");  
  127.     String host;  
  128.     if (colon < 0) {  
  129.       host = name;  
  130.     } else {  
  131.       host = name.substring(0, colon);  
  132.     }  
  133.   
  134.     hostmapLock.readLock().lock();  
  135.     try {  
  136.       DatanodeDescriptor[] nodes = map.get(host);  
  137.       // no entry  
  138.       if (nodes== null) {  
  139.         return null;  
  140.       }  
  141.       for(DatanodeDescriptor containedNode:nodes) {  
  142.         if (name.equals(containedNode.getName())) {  
  143.           return containedNode;  
  144.         }  
  145.       }  
  146.       return null;  
  147.     } finally {  
  148.       hostmapLock.readLock().unlock();  
  149.     }  
  150.   }  

另外还有一个问题,刚才说了,NameNode节点如果只以主机为单位来评估集群的负载情况,其实也是不合理的。例如,在实际的应用中,如果在某个集群里面存在主机配置参差不齐的情况,则对于那些配置很高的主机来说,它们的很多资源会处于空闲状态,其工作量相对于那些配置较低的主机来说已经饱和了。正常的情况下,集群的管理人员会在配置差的主机上部署少量的DataNode节点,在配置高的主机上部署较多的DataNode节点,因次,NameNode节点就不能仅仅只通过主机工作量来评估集群的负载情况了。至于NameNode是如何进行集群的负载均衡的,我会在以后的文章中详细介绍,但是它的实现也不一定很好,大家期望也不要太高。

     遗憾的是,Hadoop-0.2.0版本并没有这样考虑集群的负载情况,它用Host2NodesMap结构主要是能够根据某个客户端来获取其上的DataNode节点。但是,我上面猜测的并不是没有任何意义,或许将来Hadoop会把主机负载纳入到集群负载的考虑范围。



0 0