HDFS NameNode對(duì)文件塊復(fù)制相關(guān)所有事物負(fù)責(zé),它周期性接受來(lái)自于DataNode的HeartBeat和BlockReport信息嵌赠,HDFS文件塊副本的放置對(duì)于系統(tǒng)整體的可靠性和性能有關(guān)鍵性影響耘拇。
一個(gè)簡(jiǎn)單但非優(yōu)化的副本放置策略是,把副本分別放在不同機(jī)架,甚至不同IDC丢间。這樣可以防止整個(gè)機(jī)架、甚至整個(gè)IDC崩潰帶來(lái)的錯(cuò)誤驹针,但是這樣文件寫(xiě)必須在多個(gè)機(jī)架之間烘挫、甚至IDC之間傳輸,增加了副本寫(xiě)的代價(jià)柬甥。
在缺省配置下副本數(shù)是3個(gè)饮六,通常的策略是:第一個(gè)副本放在和Client相同機(jī)架的Node里(如果Client不在集群范圍,第一個(gè)Node是隨機(jī)選取不太滿或者不太忙的Node)苛蒲;第二個(gè)副本放在與第一個(gè)Node不同的機(jī)架中的Node卤橄;第三個(gè)副本放在與第二個(gè)Node所在機(jī)架里不同的Node。
Hadoop的副本放置策略在可靠性(副本在不同機(jī)架)和帶寬(只需跨越一個(gè)機(jī)架)中做了一個(gè)很好的平衡臂外。
但是狞膘,HDFS如何知道各個(gè)DataNode的網(wǎng)絡(luò)拓?fù)淝闆r呢腺律?它的機(jī)架感知功能需要 topology.script.file.name 屬性定義的可執(zhí)行文件(或者腳本)來(lái)實(shí)現(xiàn)戳护,文件提供了NodeIP對(duì)應(yīng)RackID的翻譯秸应。如果 topology.script.file.name 沒(méi)有設(shè)定,則每個(gè)IP都會(huì)翻譯成/default-rack蔫浆。
默認(rèn)情況下殖属,Hadoop機(jī)架感知是沒(méi)有啟用的,需要在NameNode機(jī)器的hadoop-site.xml里配置一個(gè)選項(xiàng)克懊,例如:
<property> <name>topology.script.file.name</name> <value>/path/to/script</value> </property>
這個(gè)配置選項(xiàng)的value指定為一個(gè)可執(zhí)行程序忱辅,通常為一個(gè)腳本七蜘,該腳本接受一個(gè)參數(shù),輸出一個(gè)值墙懂。接受的參數(shù)通常為datanode機(jī)器的ip地址橡卤,而輸出的值通常為該ip地址對(duì)應(yīng)的datanode所在的rackID,例如”/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ī)架,保存到內(nèi)存的一個(gè)map中剩瓶。
至于腳本的編寫(xiě)驹溃,就需要將真實(shí)的網(wǎng)絡(luò)拓樸和機(jī)架信息了解清楚后,通過(guò)該腳本能夠?qū)C(jī)器的ip地址正確的映射到相應(yīng)的機(jī)架上去延曙。Hadoop官方給出的腳本:http://wiki.apache.org/hadoop/topology_rack_awareness_scripts
以下分別是沒(méi)有配置機(jī)架感知信息和配置機(jī)架感知信息的hadoop HDFS進(jìn)行數(shù)據(jù)上傳時(shí)的測(cè)試結(jié)果豌鹤。
當(dāng)沒(méi)有配置機(jī)架信息時(shí),所有的機(jī)器hadoop都默認(rèn)在同一個(gè)默認(rèn)的機(jī)架下枝缔,名為 “/default-rack”布疙,這種情況下,任何一臺(tái)datanode機(jī)器愿卸,不管物理上是否屬于同一個(gè)機(jī)架灵临,都會(huì)被認(rèn)為是在同一個(gè)機(jī)架下,此時(shí)趴荸,就很容易出現(xiàn)之前提到的增添機(jī)架間網(wǎng)絡(luò)負(fù)載的情況俱诸。在沒(méi)有機(jī)架信息的情況下,namenode默認(rèn)將所有的slaves機(jī)器全部默認(rèn)為在/default-rack下赊舶,此時(shí)寫(xiě)block時(shí),三個(gè)datanode機(jī)器的選擇完全是隨機(jī)的赶诊。
當(dāng)配置了機(jī)架感知信息以后笼平,hadoop在選擇三個(gè)datanode時(shí),就會(huì)進(jìn)行相應(yīng)的判斷:
1. 如果上傳本機(jī)不是一個(gè)datanode舔痪,而是一個(gè)客戶端寓调,那么就從所有slave機(jī)器中隨機(jī)選擇一臺(tái)datanode作為第一個(gè)塊的寫(xiě)入機(jī)器(datanode1)。而此時(shí)如果上傳機(jī)器本身就是一個(gè)datanode锄码,那么就將該datanode本身作為第一個(gè)塊寫(xiě)入機(jī)器(datanode1)夺英。
2. 隨后在datanode1所屬的機(jī)架以外的另外的機(jī)架上晌涕,隨機(jī)的選擇一臺(tái),作為第二個(gè)block的寫(xiě)入datanode機(jī)器(datanode2)痛悯。
3. 在寫(xiě)第三個(gè)block前余黎,先判斷是否前兩個(gè)datanode是否是在同一個(gè)機(jī)架上,如果是在同一個(gè)機(jī)架载萌,那么就嘗試在另外一個(gè)機(jī)架上選擇第三個(gè)datanode作為寫(xiě)入機(jī)器(datanode3)惧财。而如果datanode1和datanode2沒(méi)有在同一個(gè)機(jī)架上,則在datanode2所在的機(jī)架上選擇一臺(tái)datanode作為datanode3扭仁。
4. 得到3個(gè)datanode的列表以后垮衷,從namenode返回該列表到DFSClient之前,會(huì)在namenode端首先根據(jù)該寫(xiě)入客戶端跟datanode列表中每個(gè)datanode之間的“距離”由近到遠(yuǎn)進(jìn)行一個(gè)排序乖坠,客戶端根據(jù)這個(gè)順序有近到遠(yuǎn)的進(jìn)行數(shù)據(jù)塊的寫(xiě)入搀突。
5. 當(dāng)根據(jù)“距離”排好序的datanode節(jié)點(diǎn)列表返回給DFSClient以后,DFSClient便會(huì)創(chuàng)建Block OutputStream熊泵,并向這次block寫(xiě)入pipeline中的第一個(gè)節(jié)點(diǎn)(最近的節(jié)點(diǎn))開(kāi)始寫(xiě)入block數(shù)據(jù)仰迁。
6. 寫(xiě)完第一個(gè)block以后,依次按照datanode列表中的次遠(yuǎn)的node進(jìn)行寫(xiě)入戈次,直到最后一個(gè)block寫(xiě)入成功轩勘,DFSClient返回成功,該block寫(xiě)入操作結(jié)束怯邪。
通過(guò)以上策略绊寻,namenode在選擇數(shù)據(jù)塊的寫(xiě)入datanode列表時(shí),就充分考慮到了將block副本分散在不同機(jī)架下悬秉,并同時(shí)盡量地避免了之前描述的網(wǎng)絡(luò)開(kāi)銷澄步。