研磨Hadoop源码(四)Hadoop Rack Awareness(机架感知)

来源:互联网 发布:电脑wifi无法连接网络 编辑:程序博客网 时间:2024/05/16 17:03
今天跟小伙伴讨论一下hadoop的机架感知机会,又去刨了一下hadoop源码,初略的知道了hadoop机架感知实现
     首先我们都知道hadoop默认会将数据存储三份,存储策略为本地一份,同机架内其它某一节点上一份,不同机架的某一节点上一份。这样如果本地数据损坏,节点可以从同一机架内的相邻节点拿到数据,速度肯定比从跨机架节点上拿数据要快;同时,如果整个机架的网络出现异常,也能保证在其它机架的节点上找到数据。那hadoop是怎么知道集群内机器的拓扑关系的呢??
hadoop集群会缓存了每个host与网络拓扑的关系,如何实现缓存可以通过配置项net.topology.node.switch.mapping.impl来定制,但hadoop自己有一个默认实现org.apache.hadoop.net.ScriptBasedMapping,且hadoop所有解析过的域名都会缓存到org.apache.hadoop.net.CachedDNSToSwitchMapping类中,
     具体实现:现在hadoop已经自己的所有节点域名names,需要知道所有的域名的拓扑关系,可以调用 org.apache.hadoop.net.CachedDNSToSwitchMapping.resolve(List<String> names)方法进行解析得到,源码如下(具体过程可以参看中文注释)
[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. public List<String> resolve(List<String> names) {  
  2.    // normalize all input names to be in the form of IP addresses  
  3.     //根据机器域名解析成对应的IP地址  
  4.    names = NetUtils.normalizeHostNames(names);  
  5.   
  6.    List <String> result = new ArrayList<String>(names.size());  
  7.    if (names.isEmpty()) {  
  8.      return result;  
  9.    }  
  10.      
  11.    //在缓存中根据所有的IP地址获取拓扑结构,如果获取不到则添加到未缓存的列表  
  12.    List<String> uncachedHosts = getUncachedHosts(names);  
  13.   
  14.    // Resolve the uncached hosts  
  15.    //调用ScriptBasedMapping的resolve方法解析所有未缓存IP的拓扑  
  16.    List<String> resolvedHosts = rawMapping.resolve(uncachedHosts);  
  17.    //cache them  
  18.    //将解析结果保存到map中,key:IP,value:拓扑结构(/交换机xx/机架xx)  
  19.    cacheResolvedHosts(uncachedHosts, resolvedHosts);  
  20.    //now look up the entire list in the cache  
  21.    //从缓存中获取所有的拓扑列表  
  22.    return getCachedHosts(names);  
  23.   
  24.  }  

在这里面,主要的解析逻辑在 rawMapping.resolve(uncachedHosts);中,其具体实现如下:
[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. public List<String> resolve(List<String> names) {  
  2.       List<String> m = new ArrayList<String>(names.size());  
  3.   
  4.       if (names.isEmpty()) {  
  5.         return m;  
  6.       }  
  7.       //执行的脚本名称,通过配置项net.topology.script.file.name指定  
  8.       if (scriptName == null) {  
  9.            //如果没有配置脚本,则默认所有的主机都处于/default-rack下  
  10.         for (String name : names) {  
  11.           m.add(NetworkTopology.DEFAULT_RACK);  
  12.         }  
  13.         return m;  
  14.       }  
  15.         
  16.       //运行shell脚本获取脚本执行结果,保存到List中,  
  17.       //请注意,这里返回的拓扑结构与输入的host顺序是强一致的  
  18.       String output = runResolveCommand(names);  
  19.       if (output != null) {  
  20.         StringTokenizer allSwitchInfo = new StringTokenizer(output);  
  21.         while (allSwitchInfo.hasMoreTokens()) {  
  22.           String switchInfo = allSwitchInfo.nextToken();  
  23.           m.add(switchInfo);  
  24.         }  
  25.   
  26.         if (m.size() != names.size()) {  
  27.           // invalid number of entries returned by the script  
  28.           LOG.error("Script " + scriptName + " returned "  
  29.               + Integer.toString(m.size()) + " values when "  
  30.               + Integer.toString(names.size()) + " were expected.");  
  31.           return null;  
  32.         }  
  33.       } else {  
  34.         // an error occurred. return null to signify this.  
  35.         // (exn was already logged in runResolveCommand)  
  36.         return null;  
  37.       }  
  38.   
  39.       return m;  
  40.     }  

需要注意的是,CachedDNSToSwitchMapping实现了DNSToSwitchMapping接口,因此namenode需要知道集群中某些机器的拓扑结构,只需要调用DNSToSwitchMapping.resolve(List<String> names)即可(实际上它也就是这么做的),有了机器的拓扑结构,只需要比较是否相等则可判断机器是否处于一个rack上

总结,hadoop默认所有机器都处于/default-rack rack上,用户可以通过配置net.topology.script.file.name和net.topology.node.switch.mapping.impl来定制自己的识别策略

(PS:hadoop rack脚本可参考其WIKI提供的一个例子http://wiki.apache.org/hadoop/topology_rack_awareness_scripts,同时可以通过
hdfs fsck /user/filename -files  -blocks -locations -racks 查看对应的文件block在哪些rack上)
0 0
原创粉丝点击