您的位置:首页 > 运维架构

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

2014-07-01 09:58 344 查看
今天跟小伙伴讨论一下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?





public List<String> resolve(List<String> names) {

// normalize all input names to be in the form of IP addresses

//根据机器域名解析成对应的IP地址

names = NetUtils.normalizeHostNames(names);

List <String> result = new ArrayList<String>(names.size());

if (names.isEmpty()) {

return result;

}

//在缓存中根据所有的IP地址获取拓扑结构,如果获取不到则添加到未缓存的列表

List<String> uncachedHosts = getUncachedHosts(names);

// Resolve the uncached hosts

//调用ScriptBasedMapping的resolve方法解析所有未缓存IP的拓扑

List<String> resolvedHosts = rawMapping.resolve(uncachedHosts);

//cache them

//将解析结果保存到map中,key:IP,value:拓扑结构(/交换机xx/机架xx)

cacheResolvedHosts(uncachedHosts, resolvedHosts);

//now look up the entire list in the cache

//从缓存中获取所有的拓扑列表

return getCachedHosts(names);

}

在这里面,主要的解析逻辑在 rawMapping.resolve(uncachedHosts);中,其具体实现如下:

[java] view
plaincopyprint?





public List<String> resolve(List<String> names) {

List<String> m = new ArrayList<String>(names.size());

if (names.isEmpty()) {

return m;

}

//执行的脚本名称,通过配置项net.topology.script.file.name指定

if (scriptName == null) {

//如果没有配置脚本,则默认所有的主机都处于/default-rack下

for (String name : names) {

m.add(NetworkTopology.DEFAULT_RACK);

}

return m;

}

//运行shell脚本获取脚本执行结果,保存到List中,

//请注意,这里返回的拓扑结构与输入的host顺序是强一致的

String output = runResolveCommand(names);

if (output != null) {

StringTokenizer allSwitchInfo = new StringTokenizer(output);

while (allSwitchInfo.hasMoreTokens()) {

String switchInfo = allSwitchInfo.nextToken();

m.add(switchInfo);

}

if (m.size() != names.size()) {

// invalid number of entries returned by the script

LOG.error("Script " + scriptName + " returned "

+ Integer.toString(m.size()) + " values when "

+ Integer.toString(names.size()) + " were expected.");

return null;

}

} else {

// an error occurred. return null to signify this.

// (exn was already logged in runResolveCommand)

return null;

}

return m;

}

需要注意的是,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上)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: