Hadoop機(jī)架感知
(手機(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ù)中心箱叁,那么客戶(hù)端也將首先讀本地?cái)?shù)據(jù)中心的副本。那么Hadoop是如何確定任意兩個(gè)節(jié)點(diǎn)是位于同一機(jī)架惕医,還是跨機(jī)架的呢耕漱?答案就是機(jī)架感知。 默認(rèn)情況下抬伺,hadoop的機(jī)架感知是沒(méi)有被啟用的螟够。所以,在通常情況下峡钓,hadoop集群的HDFS在選機(jī)器的時(shí)候妓笙,是隨機(jī)選擇的,也就是說(shuō)能岩,很有可能在寫(xiě)數(shù)據(jù)時(shí)寞宫,hadoop將第一塊數(shù)據(jù)block1寫(xiě)到了rack1上,然后隨機(jī)的選擇下將block2寫(xiě)入到了rack2下拉鹃,此時(shí)兩個(gè)rack之間產(chǎn)生了數(shù)據(jù)傳輸?shù)牧髁勘哺常俳酉聛?lái),在隨機(jī)的情況下毛俏,又將block3重新又寫(xiě)回了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 银锻,說(shuō)明hadoop的機(jī)架感知沒(méi)有被啟用永品。要將hadoop機(jī)架感知的功能啟用,配置非常簡(jiǎn)單击纬,在 NameNode所在節(jié)點(diǎn)的/home/bigdata/apps/hadoop/etc/hadoop的core-site.xml配置文件中配置一個(gè)選項(xiàng):topology.script.file.name/home/bigdata/apps/hadoop/etc/hadoop/topology.sh這個(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中. 至于腳本的編寫(xiě)贡茅,就需要將真實(shí)的網(wǎng)絡(luò)拓樸和機(jī)架信息了解清楚后囚巴,通過(guò)該腳本能夠?qū)C(jī)器的ip地址和機(jī)器名正確的映射到相應(yīng)的機(jī)架上去。一個(gè)簡(jiǎn)單的實(shí)現(xiàn)如下:#!/bin/bashHADOOP_CONF=/home/bigdata/apps/hadoop/etc/hadoopwhile [ $# -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 donetopology.data,格式為:節(jié)點(diǎn)(ip或主機(jī)名) /交換機(jī)xx/機(jī)架xx192.168.147.91 tbe192168147091 /dc1/rack1192.168.147.92 tbe192168147092 /dc1/rack1192.168.147.93 tbe192168147093 /dc1/rack2192.168.147.94 tbe192168147094 /dc1/rack3192.168.147.95 tbe192168147095 /dc1/rack3192.168.147.96 tbe192168147096 /dc1/rack3需要注意的是友扰,在Namenode上,該文件中的節(jié)點(diǎn)必須使用IP庶柿,使用主機(jī)名無(wú)效村怪,而Jobtracker上,該文件中的節(jié)點(diǎn)必須使用主機(jī)名浮庐,使用IP無(wú)效,所以甚负,最好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說(shuō)明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/rack1192.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)說(shuō)明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:9000org.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就可以畫(huà)出下圖所示的datanode網(wǎng)絡(luò)拓?fù)鋱D踢代。D1,R1都是交換機(jī)盲憎,最底層是datanode。則H1的rackid=/D1/R1/H1奸鬓,H1的parent是R1焙畔,R1的是D1。這些rackid信息可以通過(guò)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 相同的datanodedistance(/D1/R1/H1,/D1/R1/H2)=2 同一rack下的不同datanodedistance(/D1/R1/H1,/D1/R2/H4)=4 同一IDC下的不同datanodedistance(/D1/R1/H1,/D2/R3/H7)=6 不同IDC下的datanode