接着上一篇來說。上篇說了hadoop網絡拓撲的構成及其相應的網絡位置轉換方式,本篇主要講通過兩種方式來配置機架感知。一種是通過配置一個腳本來進行映射;另一種是通過實現DNSToSwitchMapping接口的resolve()方法來完成網絡位置的映射。
hadoop自身是沒有機架感知能力的,必須通過人爲的設定來達到這個目的。在FSNamesystem類中的resolveNetworkLocation()方法負載進行網絡位置的轉換。其中dnsToSwitchMapping變量代表了完成具體轉換工作的類,其值如下:
1 this.dnsToSwitchMapping = ReflectionUtils.newInstance(2 conf.getClass("topology.node.switch.mapping.impl", ScriptBasedMapping.class,3 DNSToSwitchMapping.class), conf);
也就是說dnsToSwitchMapping的值由“core-site.xml”配置文件中的"topology.node.switch.mapping.impl"參數指定。默認值爲ScriptBasedMapping,也就是通過讀提前寫好的腳本文件來進行網絡位置映射的。但如果這個腳本沒有配置的話,那就使用默認值“default-rack”作爲所有結點的網絡位置。
下面就先說說第一種配置機架感知的方法,使用腳本來完成網絡位置的映射。這需要在“core-site.xml”配置文件中的“topology.script.file.name”參數中指定腳本文件的位置。在wiki上找到一個官方的配置腳本,可以參考一下。首先是shell腳本:
1 HADOOP_CONF=/etc/hadoop/conf 2 3 while [ $# -gt 0 ] ; do //$#代表執行命令時輸入的參數個數 4 nodeArg=$1 5 exec< ${HADOOP_CONF}/topology.data //讀入文件 6 result="" 7 while read line ; do //循環遍歷文件內容 8 ar=( $line ) 9 if [ "${ar[0]}" = "$nodeArg" ] ; then10 result="${ar[1]}"11 fi12 done 13 shift 14 if [ -z "$result" ] ; then15 echo -n "/default/rack "16 else17 echo -n "$result "18 fi19 done
topology.data文件格式如下:
tt156 /dc1/rack1 tt163 /dc1/rack1 tt164 /dc1/rack2 tt165 /dc1/rack210.32.11.156 /dc1/rack110.32.11.163 /dc1/rack110.32.11.164 /dc1/rack210.32.11.165 /dc1/rack2
我是把原來topology.data文件內容改了下,把hostname也添加進去了,這樣保證正確性。因爲JobTracker是通過hostname進行映射的。
網上也有用Python腳本和C語言寫的,但我對Python不是很熟,所以在這裏就不說了。總結上邊的內容,可以知道,不管用什麼腳本來寫,最重要的就是接收參數,完成網絡位置映射並將結果輸出。這樣系統就能夠接收到合適結果。
第二種配置機架感知的方法是通過實現DNSToSwitchMapping接口,重寫resolve()方法完成的。這就需要自己寫個java類來完成映射了。然後在“core-site.xml”配置文件中的“topology.node.switch.mapping.impl”指定自己的實現類。這樣的話,在進行網絡位置解析的時候,就會調用自己類中的resolve()方法來完成轉換了。我寫的比較簡單,能完成功能就好,代碼如下(大神飛過):
1 public class MyResolveNetworkTopology implements DNSToSwitchMapping { 2 3 private String[] hostnameLists = {"tt156", "tt163", "tt164", "tt165"}; 4 private String[] ipLists = {"10.32.11.156", "10.32.11.163", "10.32.11.164", "10.32.11.165"}; 5 private String[] resolvedLists = {"/dc1/rack1", "/dc1/rack1", "/dc1/rack2", "/dc1/rack2"}; 6 7 @Override 8 public List<String> resolve(List<String> names) { 9 names = NetUtils.normalizeHostNames(names);10 11 List <String> result = new ArrayList<String>(names.size());12 if (names.isEmpty()) {13 return result;14 }15 16 for (int i = 0; i < names.size(); i++) {17 String name = names.get(i);18 for(int j = 0; j < hostnameLists.length; j++){19 if(name.equals(hostnameLists[j])) {20 result.add(resolvedLists[j]);21 } else if(name.equals(ipLists[j])) {22 result.add(resolvedLists[j]);23 }24 }25 }26 return result;27 }28 }
我把這個自定義的MyResolveNetworkTopology類放在了core包的org.apache.hadoop.net目錄下。所以在“core-site.xml”文件中的配置如下:
<property> <name>topology.node.switch.mapping.impl</name> <value>org.apache.hadoop.net.MyResolveNetworkTopology</value> <description> The default implementation of the DNSToSwitchMapping. It invokes a script specified in topology.script.file.name to resolve node names. If the value for topology.script.file.name is not set, the default value of DEFAULT_RACK is returned for all node names. </description></property>
以上兩種方法在配置完成後,會在NameNode和JobTracker的log中打印出如下信息:
2015-05-26 20:47:20,665 INFO org.apache.hadoop.net.NetworkTopology: Adding a new node: /dc1/rack1/tt163 2015-05-26 20:47:20,689 INFO org.apache.hadoop.net.NetworkTopology: Adding a new node: /dc1/rack1/tt156 .......
這就說明機架感知配置成功了。
總結一下以上兩種方式。通過腳本配置的方式,靈活性很高,但是執行效率較低。因爲系統要從jvm轉到shell去執行;java類的方式性能較高,但是編譯之後就無法改變了,所以靈活程度較低。所以要根據具體情況來選擇策略.