好程式設計師大資料學習路線分享Hadoop機架感知

好程式設計師發表於2020-06-04

  好程式設計師 大資料學習路線分享Hadoop機架感知 1.背景 Hadoop在設計時考慮到資料的安全與高效,資料檔案預設在HDFS上存放三份,儲存策略為本地一份,同機架內其它某一節點上一份,不同機架的某一節點上一份。這樣如果本地資料損壞,節點可以從同一機架內的相鄰節點拿到資料,速度肯定比從跨機架節點上拿資料要快;同時,如果整個機架的網路出現異常,也能保證在其它機架的節點上找到資料。為了降低整體的頻寬消耗和讀取延時,HDFS會盡量讓讀取程式讀取離它最近的副本。如果在讀取程式的同一個機架上有一個副本,那麼就讀取該副本。如果一個HDFS叢集跨越多個資料中心,那麼客戶端也將首先讀本地資料中心的副本。那麼Hadoop是如何確定任意兩個節點是位於同一機架,還是跨機架的呢?答案就是機架感知。

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

2.配置

預設情況下,namenode啟動時候日誌是這樣的:

2013-09-22 17:27:26,423 INFO org.apache.hadoop.net.NetworkTopology: Adding a new node: /default-rack/ 192.168.147.92:50010

每個IP 對應的機架ID都是 /default-rack ,說明hadoop的機架感知沒有被啟用。

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

<property>

<name>topology.script.file.name</name>

<value>/home/bigdata/apps/hadoop/etc/hadoop/topology.sh</value>

</property>

這個配置選項的value指定為一個可執行程式,通常為一個指令碼,該指令碼接受一個引數,輸出一個值。接受的引數通常為某臺datanode機器的ip地址,而輸出的值通常為該ip地址對應的datanode所在的rack,例如”/rack1”。Namenode啟動時,會判斷該配置選項是否為空,如果非空,則表示已經啟用機架感知的配置,此時namenode會根據配置尋找該指令碼,並在接收到每一個datanode的heartbeat時,將該datanode的ip地址作為引數傳給該指令碼執行,並將得到的輸出作為該datanode所屬的機架ID,儲存到記憶體的一個map中.

至於指令碼的編寫,就需要將真實的網路拓樸和機架資訊瞭解清楚後,透過該指令碼能夠將機器的ip地址和機器名正確的對映到相應的機架上去。一個簡單的實現如下:

#!/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,格式為:節點(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和主機名都配上。

這樣配置後,namenode啟動時候日誌是這樣的:

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的機架感知已經被啟用了。

檢視HADOOP機架資訊命令:

./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.增加資料節點,不重啟NameNode

假設Hadoop叢集在192.168.147.68上部署了NameNode和DataNode,啟用了機架感知,執行bin/hadoop dfsadmin -printTopology看到的結果:

Rack: /dc1/rack1

192.168.147.68:50010 (dbj68)

現在想增加一個物理位置在rack2的資料節點192.168.147.69到叢集中,不重啟NameNode。

首先,修改NameNode節點的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啟動資料節點dbj69,任意節點執行bin/hadoop dfsadmin -printTopology 看到的結果:

Rack: /dc1/rack1

192.168.147.68:50010 (dbj68)

Rack: /dc1/rack2

192.168.147.69:50010 (dbj69)

說明hadoop已經感知到了新加入的節點dbj69。

注意:如果不將dbj69的配置加入到topology.data中,執行sbin/hadoop-daemons.sh start datanode啟動資料節點dbj69,datanode日誌中會有異常發生,導致dbj69啟動不成功。

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.節點間距離計算

有了機架感知,NameNode就可以畫出下圖所示的datanode網路拓撲圖。D1,R1都是交換機,最底層是datanode。則H1的rackid=/D1/R1/H1,H1的parent是R1,R1的是D1。這些rackid資訊可以透過topology.script.file.name配置。有了這些rackid資訊就可以計算出任意兩臺datanode之間的距離,得到最優的存放策略,最佳化整個叢集的網路頻寬均衡以及資料最優分配。

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


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69913864/viewspace-2696066/,如需轉載,請註明出處,否則將追究法律責任。

相關文章