1. 程式人生 > >hadoop之 hadoop 機架感知

hadoop之 hadoop 機架感知

信息 內容 其它 heartbeat 循環 yun 一次 能力 高效

1.背景

Hadoop在設計時考慮到數據的安全與高效,數據文件默認在HDFS上存放三份,存儲策略為本地一份,同機架內其它某一節點上一份,不同機架的某一節點上一份。這樣如果本地數據損壞,節點可以從同一機架內的相鄰節點拿到數據,速度肯定比從跨機架節點上拿數據要快;同時,如果整個機架的網絡出現異常,也能保證在其它機架的節點上找到數據。為了降低整體的帶寬消耗和讀取延時,HDFS會盡量讓讀取程序讀取離它最近的副本。如果在讀取程序的同一個機架上有一個副本,那麽就讀取該副本。如果一個HDFS集群跨越多個數據中心,那麽客戶端也將首先讀本地數據中心的副本。那麽Hadoop是如何確定任意兩個節點是位於同一機架,還是跨機架的呢?答案就是機架感知。

默認情況下,hadoop的機架感知是沒有被啟用的。所以,在通常情況下,hadoop集群的HDFS在選機器的時候,是隨機選擇的,也就是說,很有可能在寫數據時,hadoop將第一塊數據block1寫到了rack1上,然後隨機的選擇下將block2寫入到了rack2下,此時兩個rack之間產生了數據傳輸的流量,再接下來,在隨機的情況下,又將block3重新又寫回了rack1,此時,兩個rack之間又產生了一次數據流量。在job處理的數據量非常的大,或者往hadoop推送的數據量非常大的時候,這種情況會造成rack之間的網絡流量成倍的上升,成為性能的瓶頸,進而影響作業的性能以至於整個集群的服務

2.配置

兩種方式來配置機架感知。一種是通過配置一個腳本來進行映射;另一種是通過實現DNSToSwitchMapping接口的resolve()方法來完成網絡位置的映射。

  hadoop自身是沒有機架感知能力的,必須通過人為的設定來達到這個目的。在FSNamesystem類中的resolveNetworkLocation()方法負載進行網絡位置的轉換。其中dnsToSwitchMapping變量代表了完成具體轉換工作的類,其值如下:

this.dnsToSwitchMapping = ReflectionUtils.newInstance(
conf.getClass("topology.node.switch.mapping.impl", ScriptBasedMapping.class,
DNSToSwitchMapping.class), conf);

也就是說dnsToSwitchMapping的值由“core-site.xml”配置文件中的"topology.node.switch.mapping.impl"參數指定。默認值為ScriptBasedMapping,也就是通過讀提前寫好的腳本文件來進行網絡位置映射的。但如果這個腳本沒有配置的話,那就使用默認值“default-rack”作為所有結點的網絡位置。

下面就先說說第一種配置機架感知的方法,使用腳本來完成網絡位置的映射。

要將hadoop機架感知的功能啟用,配置非常簡單,在NameNode所在節點的/home/bigdata/apps/hadoop-talkyun/etc/hadoop的core-site.xml配置文件中配置一個選項:

<property>
<name>topology.script.file.name</name>
<value>/home/bigdata/apps/hadoop-talkyun/etc/hadoop/topology.sh</value>
</property>
這個配置選項的value指定為一個可執行程序,通常為一個腳本,該腳本接受一個參數,輸出一個值。接受的參數通常為某臺datanode機器的ip地址,而輸出的值通常為該ip地址對應的datanode所在的rack,例如”/rack1”。Namenode啟動時,會判斷該配置選項是否為空,如果非空,則表示已經啟用機架感知的配置,此時namenode會根據配置尋找該腳本,並在接收到每一個datanode的heartbeat時,將該datanode的ip地址作為參數傳給該腳本運行,並將得到的輸出作為該datanode所屬的機架ID,保存到內存的一個map中.

至於腳本的編寫,就需要將真實的網絡拓樸和機架信息了解清楚後,通過該腳本能夠將機器的ip地址和機器名正確的映射到相應的機架上去。一個簡單的實現如下:


在wiki上找到一個官方的配置腳本,可以參考一下。首先是shell腳本:
topology.sh:

#!/bin/bash
HADOOP_CONF=/etc/hadoop/conf
while [ $# -gt 0 ] ; do //$#代表執行命令時輸入的參數個數
nodeArg=$1
exec< ${HADOOP_CONF}/topology.data //讀入文件
result=""
while read line ; do //循環遍歷文件內容
ar=( $line )
if [ "${ar[0]}" = "$nodeArg" ] ; then
result="${ar[1]}"
fi
done
shift
if [ -z "$result" ] ; then
echo -n "/default/rack "
else
echo -n "$result "
fi
done

topology.data,格式為:節點(ip或主機名) /交換機xx/機架xx

192.168.147.91 tbe192168147091 /dc1/rack1
192.168.147.92 tbe192168147092 /dc1/rack1
192.168.147.93 tbe192168147093 /dc1/rack2
192.168.147.94 tbe192168147094 /dc1/rack3
192.168.147.95 tbe192168147095 /dc1/rack3
192.168.147.96 tbe192168147096 /dc1/rack3
需要註意的是,在Namenode上,該文件中的節點必須使用IP,使用主機名無效,而Jobtracker上,該文件中的節點必須使用主機名,使用IP無效,所以,最好ip和主機名都配上。

第二種配置機架感知的方法是通過實現DNSToSwitchMapping接口,重寫resolve()方法完成的。這就需要自己寫個java類來完成映射了。然後在“core-site.xml”配置文件中的“topology.node.switch.mapping.impl”指定自己的實現類。這樣的話,在進行網絡位置解析的時候,就會調用自己類中的resolve()方法來完成轉換了。我寫的比較簡單,能完成功能就好,代碼如下(大神飛過):

public class MyResolveNetworkTopology implements DNSToSwitchMapping {

private String[] hostnameLists = {"tt156", "tt163", "tt164", "tt165"};
private String[] ipLists = {"10.32.11.156", "10.32.11.163", "10.32.11.164", "10.32.11.165"};
private String[] resolvedLists = {"/dc1/rack1", "/dc1/rack1", "/dc1/rack2", "/dc1/rack2"};

@Override
public List<String> resolve(List<String> names) {
names = NetUtils.normalizeHostNames(names);

List <String> result = new ArrayList<String>(names.size());
if (names.isEmpty()) {
return result;
}

for (int i = 0; i < names.size(); i++) {
String name = names.get(i);
for(int j = 0; j < hostnameLists.length; j++){
if(name.equals(hostnameLists[j])) {
result.add(resolvedLists[j]);
} else if(name.equals(ipLists[j])) {
result.add(resolvedLists[j]);
}
}
}
return result;
}

我把這個自定義的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中打印出如下信息:
INFO org.apache.hadoop.net.NetworkTopology: Adding a new node: /dc1/rack3/ 192.168.147.94:50010

 這就說明機架感知配置成功了。

  總結一下以上兩種方式。通過腳本配置的方式,靈活性很高,但是執行效率較低。因為系統要從jvm轉到shell去執行;java類的方式性能較高,但是編譯之後就無法改變了,所以靈活程度較低。所以要根據具體情況來選擇策略.


補充:
查看HADOOP機架信息命令:
./hadoop dfsadmin -printTopology

說明:整理於網絡

source: http://www.cnblogs.com/gwgyk/p/4531947.html 等

hadoop之 hadoop 機架感知