Hadoop 機(jī)架感知配置和原理
Hadoop機(jī)架感知
1.背景
Hadoop在設(shè)計(jì)時(shí)考慮到數(shù)據(jù)的安全與高效,數(shù)據(jù)文件默認(rèn)在HDFS上存放三份,存儲(chǔ)策略為本地一份,
同機(jī)架內(nèi)其它某一節(jié)點(diǎn)上一份,不同機(jī)架的某一節(jié)點(diǎn)上一份。
這樣如果本地?cái)?shù)據(jù)損壞,節(jié)點(diǎn)可以從同一機(jī)架內(nèi)的相鄰節(jié)點(diǎn)拿到數(shù)據(jù),速度肯定比從跨機(jī)架節(jié)點(diǎn)上拿數(shù)據(jù)要快;
同時(shí),如果整個(gè)機(jī)架的網(wǎng)絡(luò)出現(xiàn)異常,也能保證在其它機(jī)架的節(jié)點(diǎn)上找到數(shù)據(jù)。
為了降低整體的帶寬消耗和讀取延時(shí),HDFS會(huì)盡量讓讀取程序讀取離它最近的副本。
如果在讀取程序的同一個(gè)機(jī)架上有一個(gè)副本,那么就讀取該副本。
如果一個(gè)HDFS集群跨越多個(gè)數(shù)據(jù)中心,那么客戶端也將首先讀本地?cái)?shù)據(jù)中心的副本。
那么Hadoop是如何確定任意兩個(gè)節(jié)點(diǎn)是位于同一機(jī)架,還是跨機(jī)架的呢?答案就是機(jī)架感知。
默認(rèn)情況下,hadoop的機(jī)架感知是沒有被啟用的。所以,在通常情況下,hadoop集群的HDFS在選機(jī)器的時(shí)候,是隨機(jī)選擇的,也就是說,
很有可能在寫數(shù)據(jù)時(shí),hadoop將第一塊數(shù)據(jù)block1寫到了rack1上,然后隨機(jī)的選擇下將block2寫入到了rack2下,
此時(shí)兩個(gè)rack之間產(chǎn)生了數(shù)據(jù)傳輸?shù)牧髁?,再接下來,在隨機(jī)的情況下,又將block3重新又寫回了rack1,
此時(shí),兩個(gè)rack之間又產(chǎn)生了一次數(shù)據(jù)流量。
在job處理的數(shù)據(jù)量非常的大,或者往hadoop推送的數(shù)據(jù)量非常大的時(shí)候,這種情況會(huì)造成rack之間的網(wǎng)絡(luò)流量成倍的上升,成為性能的瓶頸,
進(jìn)而影響作業(yè)的性能以至于整個(gè)集群的服務(wù)
2.配置
默認(rèn)情況下,namenode啟動(dòng)時(shí)候日志是這樣的:
2013-09-22 17:27:26,423 INFO org.apache.hadoop.net.NetworkTopology: Adding a new node: /default-rack/ 192.168.147.92:50010
每個(gè)IP 對(duì)應(yīng)的機(jī)架ID都是 /default-rack ,說明hadoop的機(jī)架感知沒有被啟用。
要將hadoop機(jī)架感知的功能啟用,配置非常簡(jiǎn)單,在 NameNode所在節(jié)點(diǎn)的/home/bigdata/apps/hadoop/etc/hadoop的core-site.xml配置文件中配置一個(gè)選項(xiàng):
<property>
<name>topology.script.file.name</name>
<value>/home/bigdata/apps/hadoop/etc/hadoop/topology.sh</value>
</property>
這個(gè)配置選項(xiàng)的value指定為一個(gè)可執(zhí)行程序,通常為一個(gè)腳本,該腳本接受一個(gè)參數(shù),輸出一個(gè)值。
接受的參數(shù)通常為某臺(tái)datanode機(jī)器的ip地址,而輸出的值通常為該ip地址對(duì)應(yīng)的datanode所在的rack,例如”/rack1”。
Namenode啟動(dòng)時(shí),會(huì)判斷該配置選項(xiàng)是否為空,如果非空,則表示已經(jīng)啟用機(jī)架感知的配置,此時(shí)namenode會(huì)根據(jù)配置尋找該腳本,
并在接收到每一個(gè)datanode的heartbeat時(shí),將該datanode的ip地址作為參數(shù)傳給該腳本運(yùn)行,并將得到的輸出作為該datanode所屬的機(jī)架ID,
保存到內(nèi)存的一個(gè)map中.
至于腳本的編寫,就需要將真實(shí)的網(wǎng)絡(luò)拓樸和機(jī)架信息了解清楚后,通過該腳本能夠?qū)C(jī)器的ip地址和機(jī)器名正確的映射到相應(yīng)的機(jī)架上去。
一個(gè)簡(jiǎn)單的實(shí)現(xiàn)如下:
#!/bin/bash
HADOOP_CONF=/home/bigdata/apps/hadoop/etc/hadoop
while [ $# -gt 0 ] ; do
nodeArg=$1
exec<${HADOOP_CONF}/topology.data
result=""
while read line ; do
ar=( $line )
if [ "${ar[0]}" = "$nodeArg" ]||[ "${ar[1]}" = "$nodeArg" ]; then
result="${ar[2]}"
fi
done
shift
if [ -z "$result" ] ; then
echo -n "/default-rack"
else
echo -n "$result"
fi
done
topology.data,格式為:節(jié)點(diǎn)(ip或主機(jī)名) /交換機(jī)xx/機(jī)架xx
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上,該文件中的節(jié)點(diǎn)必須使用IP,使用主機(jī)名無效,
而Jobtracker上,該文件中的節(jié)點(diǎn)必須使用主機(jī)名,使用IP無效,所以,最好ip和主機(jī)名都配上。
這樣配置后,namenode啟動(dòng)時(shí)候日志是這樣的:
2013-09-23 17:16:27,272 INFO org.apache.hadoop.net.NetworkTopology: Adding a new node: /dc1/rack3/ 192.168.147.94:50010
說明hadoop的機(jī)架感知已經(jīng)被啟用了。
查看HADOOP機(jī)架信息命令:
./hadoop dfsadmin -printTopology
Rack: /dc1/rack1
192.168.147.91:50010 (tbe192168147091)
192.168.147.92:50010 (tbe192168147092)
Rack: /dc1/rack2
192.168.147.93:50010 (tbe192168147093)
Rack: /dc1/rack3
192.168.147.94:50010 (tbe192168147094)
192.168.147.95:50010 (tbe192168147095)
192.168.147.96:50010 (tbe192168147096)
3.增加數(shù)據(jù)節(jié)點(diǎn),不重啟NameNode
假設(shè)Hadoop集群在192.168.147.68上部署了NameNode和DataNode,啟用了機(jī)架感知,執(zhí)行bin/hadoop dfsadmin -printTopology看到的結(jié)果:
Rack: /dc1/rack1
192.168.147.68:50010 (dbj68)
現(xiàn)在想增加一個(gè)物理位置在rack2的數(shù)據(jù)節(jié)點(diǎn)192.168.147.69到集群中,不重啟NameNode。
首先,修改NameNode節(jié)點(diǎn)的topology.data的配置,加入:192.168.147.69 dbj69 /dc1/rack2,保存。
192.168.147.68 dbj68 /dc1/rack1
192.168.147.69 dbj69 /dc1/rack2
然后,sbin/hadoop-daemons.sh start datanode啟動(dòng)數(shù)據(jù)節(jié)點(diǎn)dbj69,任意節(jié)點(diǎn)執(zhí)行bin/hadoop dfsadmin -printTopology 看到的結(jié)果:
Rack: /dc1/rack1
192.168.147.68:50010 (dbj68)
Rack: /dc1/rack2
192.168.147.69:50010 (dbj69)
說明hadoop已經(jīng)感知到了新加入的節(jié)點(diǎn)dbj69。
注意:如果不將dbj69的配置加入到topology.data中,
執(zhí)行sbin/hadoop-daemons.sh start datanode啟動(dòng)數(shù)據(jù)節(jié)點(diǎn)dbj69,datanode日志中會(huì)有異常發(fā)生,導(dǎo)致dbj69啟動(dòng)不成功。
2013-11-21 10:51:33,502 FATAL org.apache.hadoop.hdfs.server.datanode.DataNode: Initialization failed for block pool Block pool BP-1732631201-192.168.147.68-1385000665316 (storage id DS-878525145-192.168.147.69-50010-1385002292231) service to dbj68/192.168.147.68:9000
org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.net.NetworkTopology$InvalidTopologyException): Invalid network topology. You cannot have a rack and a non-rack node at the same level of the network topology.
at org.apache.hadoop.net.NetworkTopology.add(NetworkTopology.java:382)
at org.apache.hadoop.hdfs.server.blockmanagement.DatanodeManager.registerDatanode(DatanodeManager.java:746)
at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.registerDatanode(FSNamesystem.java:3498)
at org.apache.hadoop.hdfs.server.namenode.NameNodeRpcServer.registerDatanode(NameNodeRpcServer.java:876)
at org.apache.hadoop.hdfs.protocolPB.DatanodeProtocolServerSideTranslatorPB.registerDatanode(DatanodeProtocolServerSideTranslatorPB.java:91)
at org.apache.hadoop.hdfs.protocol.proto.DatanodeProtocolProtos$DatanodeProtocolService$2.callBlockingMethod(DatanodeProtocolProtos.java:20018)
at org.apache.hadoop.ipc.ProtobufRpcEngine$Server$ProtoBufRpcInvoker.call(ProtobufRpcEngine.java:453)
at org.apache.hadoop.ipc.RPC$Server.call(RPC.java:1002)
at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:1701)
at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:1697)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:415)
at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1408)
at org.apache.hadoop.ipc.Server$Handler.run(Server.java:1695)
at org.apache.hadoop.ipc.Client.call(Client.java:1231)
at org.apache.hadoop.ipc.ProtobufRpcEngine$Invoker.invoke(ProtobufRpcEngine.java:202)
at $Proxy10.registerDatanode(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.apache.hadoop.io.retry.RetryInvocationHandler.invokeMethod(RetryInvocationHandler.java:164)
at org.apache.hadoop.io.retry.RetryInvocationHandler.invoke(RetryInvocationHandler.java:83)
at $Proxy10.registerDatanode(Unknown Source)
at org.apache.hadoop.hdfs.protocolPB.DatanodeProtocolClientSideTranslatorPB.registerDatanode(DatanodeProtocolClientSideTranslatorPB.java:149)
at org.apache.hadoop.hdfs.server.datanode.BPServiceActor.register(BPServiceActor.java:619)
at org.apache.hadoop.hdfs.server.datanode.BPServiceActor.connectToNNAndHandshake(BPServiceActor.java:221)
at org.apache.hadoop.hdfs.server.datanode.BPServiceActor.run(BPServiceActor.java:660)
at java.lang.Thread.run(Thread.java:722)
4.節(jié)點(diǎn)間距離計(jì)算
有了機(jī)架感知,NameNode就可以畫出下圖所示的datanode網(wǎng)絡(luò)拓?fù)鋱D。D1,R1都是交換機(jī),最底層是datanode。
則H1的rackid=/D1/R1/H1,H1的parent是R1,R1的是D1。這些rackid信息可以通過topology.script.file.name配置。
有了這些rackid信息就可以計(jì)算出任意兩臺(tái)datanode之間的距離,得到最優(yōu)的存放策略,優(yōu)化整個(gè)集群的網(wǎng)絡(luò)帶寬均衡以及數(shù)據(jù)最優(yōu)分配。
distance(/D1/R1/H1,/D1/R1/H1)=0 相同的datanode
distance(/D1/R1/H1,/D1/R1/H2)=2 同一rack下的不同datanode
distance(/D1/R1/H1,/D1/R2/H4)=4 同一IDC下的不同datanode
distance(/D1/R1/H1,/D2/R3/H7)=6 不同IDC下的datanode