數(shù)據(jù)流
讀取文件數(shù)據(jù)的剖析
為了知道客戶端與HDFS商架,NameNode,DataNode交互過程中數(shù)據(jù)的流向萝挤,請(qǐng)看圖3-2,這張圖顯示了讀取文件過程中主要的事件順序围苫。客戶端通過調(diào)用FileSystem對(duì)象的open()方法打開一個(gè)希望從中讀取數(shù)據(jù)的文件殖妇,對(duì)于HDFS來說询筏,F(xiàn)ileSystem是一個(gè)DistributedFileSystem的實(shí)例對(duì)象(圖3-2 步驟1)。DistributedFileSystem遠(yuǎn)程調(diào)用名稱節(jié)點(diǎn)(NameNode)得到文件開頭幾個(gè)塊的位置叠纹。對(duì)于每一個(gè)塊季研,名稱節(jié)點(diǎn)返回包含這個(gè)塊復(fù)本的所有數(shù)據(jù)節(jié)點(diǎn)(DataNode)的地址。進(jìn)一步誉察,這些數(shù)據(jù)節(jié)點(diǎn)會(huì)根據(jù)集群的網(wǎng)絡(luò)拓?fù)浣Y(jié)構(gòu)按照距離客戶端的遠(yuǎn)近進(jìn)行排序与涡。如果客戶端本身是一個(gè)數(shù)據(jù)節(jié)點(diǎn)(例如一個(gè)MapReduce任務(wù)),而這個(gè)數(shù)據(jù)節(jié)點(diǎn)包含要讀取的塊的復(fù)本持偏,則客戶端會(huì)直接從本地讀取驼卖。
DistributedFileSystem返回一個(gè)FSDataInputStream對(duì)象給客戶端,用于從文件中讀取數(shù)據(jù)鸿秆。FSDataInputStream是一個(gè)輸入流酌畜,支持文件尋位(seek)。FSDataInputStream里包裝了一個(gè)DFSInputStream類卿叽,這個(gè)類支持?jǐn)?shù)據(jù)節(jié)點(diǎn)和名稱節(jié)點(diǎn)的I/O操作桥胞。
客戶端調(diào)用read()方法從流中讀取數(shù)據(jù)。DFSInputStream存儲(chǔ)了文件中開頭幾個(gè)塊所在的數(shù)據(jù)節(jié)點(diǎn)的地址考婴。首先連接第一個(gè)塊所在的最近的數(shù)據(jù)節(jié)點(diǎn)贩虾,數(shù)據(jù)從數(shù)據(jù)節(jié)點(diǎn)被讀取到客戶端,然后不斷地從這個(gè)流中讀取(步驟4)直接這個(gè)塊數(shù)據(jù)被讀完蕉扮,然后DFSInputStream將會(huì)關(guān)閉到這個(gè)數(shù)據(jù)節(jié)點(diǎn)的連接整胃,尋找下一個(gè)塊所在的最近的數(shù)據(jù)節(jié)點(diǎn)(步驟5)。這一系列操作對(duì)客戶端來說是透明的喳钟,它不用管屁使。從客戶端的角度來看,它僅僅是在讀取一個(gè)連續(xù)的數(shù)據(jù)流奔则。
塊按順序依次被讀取蛮寂。當(dāng)客戶端從數(shù)據(jù)流中讀數(shù)的時(shí)候,DFSInputStream依次建立和關(guān)閉和數(shù)據(jù)節(jié)點(diǎn)的連接易茬。如果需要酬蹋,DistributedFileSystem將再次調(diào)用名稱節(jié)點(diǎn)得到下一批塊所有數(shù)據(jù)節(jié)點(diǎn)的位置及老。當(dāng)客戶端完成了所有數(shù)據(jù)的讀取,它會(huì)調(diào)用FSDataInputStream的close()方法關(guān)閉流(步驟6)范抓。
在讀取的過程中骄恶,如果DFSInputStream在與數(shù)據(jù)節(jié)點(diǎn)交互的過程中出現(xiàn)了錯(cuò)誤,它將會(huì)嘗試當(dāng)前塊所在的最近的下一個(gè)數(shù)據(jù)節(jié)點(diǎn)匕垫。它也會(huì)記住那些交互失敗的數(shù)據(jù)節(jié)點(diǎn)以便讀取其它塊時(shí)不再在這些失敗的數(shù)據(jù)節(jié)點(diǎn)中讀取僧鲁。DFSInputStream也會(huì)校驗(yàn)從數(shù)據(jù)節(jié)點(diǎn)傳過來的數(shù)據(jù),如果塊中數(shù)據(jù)損壞了象泵,它將嘗試從另一個(gè)包含這個(gè)塊復(fù)本的數(shù)據(jù)節(jié)點(diǎn)中讀取寞秃。它也會(huì)向名稱節(jié)點(diǎn)報(bào)告這個(gè)損壞的塊。
這樣設(shè)計(jì)一個(gè)重要的方面是客戶端直接與數(shù)據(jù)節(jié)點(diǎn)交互偶惠,并通過名稱節(jié)點(diǎn)的引導(dǎo)春寿,找到每一個(gè)塊所在的最好的數(shù)據(jù)節(jié)點(diǎn)。這樣設(shè)計(jì)可以讓HDFS響應(yīng)大量同時(shí)并發(fā)請(qǐng)求的客戶端忽孽。因?yàn)閿?shù)據(jù)分布在集群中所有的數(shù)據(jù)節(jié)點(diǎn)中绑改。而且,名稱節(jié)點(diǎn)僅僅需要響應(yīng)獲取塊所有位置的請(qǐng)求(這個(gè)位置信息存儲(chǔ)在內(nèi)存中扒腕,所以非常高效)而不需要響應(yīng)獲取文件數(shù)據(jù)的請(qǐng)求绢淀。如果名稱節(jié)點(diǎn)還響應(yīng)讀取文件數(shù)據(jù)的請(qǐng)求,那么隨著客戶端數(shù)據(jù)增多瘾腰,很快會(huì)出現(xiàn)瓶頸皆的。
Hadoop網(wǎng)絡(luò)拓?fù)浣Y(jié)構(gòu)
本地網(wǎng)絡(luò)的兩個(gè)節(jié)點(diǎn)對(duì)彼此"關(guān)閉"是什么意思呢?在大批量數(shù)據(jù)處理環(huán)境中,限制速度的因素是節(jié)點(diǎn)之前傳輸?shù)乃俾侍E瑁瑤拵缀鯇?duì)速度沒有一點(diǎn)貢獻(xiàn)费薄,所以可以用節(jié)點(diǎn)間的帶寬做為衡量節(jié)點(diǎn)間距離的尺碼。但在實(shí)踐中并不直接去測(cè)試兩個(gè)節(jié)點(diǎn)間的帶寬栖雾,因?yàn)檫@很困難楞抡。Hadoop采取了一個(gè)簡單的途徑,網(wǎng)絡(luò)以樹的形式表示析藕,兩個(gè)節(jié)點(diǎn)的距離等于各自距離他們共同上層節(jié)點(diǎn)的距離之和召廷。樹中的層級(jí)并不是預(yù)先設(shè)定好的,通常層級(jí)中有數(shù)據(jù)中心账胧,機(jī)架(Rack)和正在運(yùn)行進(jìn)程的節(jié)點(diǎn)竞慢。下面場(chǎng)景中帶寬依次遞減:圖3-3更加形象顯示了上面示例:
- 相同節(jié)點(diǎn)上的處理
- 同一機(jī)架不同節(jié)點(diǎn)上的處理
- 同一數(shù)據(jù)中心不同機(jī)架中節(jié)點(diǎn)上的處理
- 不同數(shù)據(jù)中心中節(jié)點(diǎn)上的處理
例如:節(jié)點(diǎn)n1,在機(jī)架r1上,機(jī)架在數(shù)據(jù)中心d1上治泥。用/d1/r1/n1筹煮,以這為列,來看看下面四個(gè)場(chǎng)景中節(jié)點(diǎn)間距離:- distance(/d1/r1/n1,/d1/r1/n1)=0(相同節(jié)點(diǎn)上的處理)
- distance(/d1/r1/n1,/d1/r1/n2)=2(相同機(jī)架上不同節(jié)點(diǎn))
- distance(/d1/r1/n1,/d1/r2/n3)=4(相同數(shù)據(jù)中心不同節(jié)點(diǎn))
- distance(/d1/r1/n1,/d2/r3/n4)=6(不同數(shù)據(jù)中心節(jié)點(diǎn))
圖3-3:hadoop中節(jié)點(diǎn)間距離最后居夹,你要知道hadoop并不知道你的網(wǎng)絡(luò)拓?fù)鋱D败潦,需要你進(jìn)行配置本冲。然而,默認(rèn)的情況下劫扒,hadoop會(huì)假設(shè)所有節(jié)點(diǎn)在同一數(shù)據(jù)中心中一機(jī)架上檬洞。對(duì)于小型集群,確實(shí)是這種情況沟饥,這樣的話疮胖,就不需要進(jìn)行額外的配置。
寫入數(shù)據(jù)到文件的剖析
下一步闷板,我們將看看數(shù)據(jù)怎么寫入到HDFS中的。雖然這是很細(xì)節(jié)的東西院塞,但它有助于理解HDFS模型如何保證數(shù)據(jù)一致遮晚。
我們考慮這一種情況,在HDFS中創(chuàng)建一個(gè)新文件拦止,寫入數(shù)據(jù)县遣,然后關(guān)閉文件。如圖3-4所示:客戶端通過調(diào)用DistributedFileSystem類的create()方法創(chuàng)建文件(圖3-4步驟1)汹族。DistributedFileSystem遠(yuǎn)程調(diào)用名稱節(jié)點(diǎn)在文件系統(tǒng)的名稱空間中創(chuàng)建一個(gè)新文件萧求,沒有塊與這個(gè)新文件關(guān)聯(lián)(步驟2)。名稱節(jié)點(diǎn)做各種各樣的檢查確保文件之前沒有被創(chuàng)建過顶瞒,而且客戶端有權(quán)限創(chuàng)建這個(gè)文件夸政。如果檢查通過,名稱節(jié)點(diǎn)將會(huì)記錄這個(gè)新文件榴徐,否則將創(chuàng)建失敗守问,拋給客戶端一個(gè)IOException異常。如果成功創(chuàng)建坑资,則DistributedFileSystem返回一個(gè)FSDataOutputStream對(duì)象給客戶端耗帕,以便客戶端寫入數(shù)據(jù)。正如讀數(shù)據(jù)那樣袱贮,F(xiàn)SDataOutputStream封閉了DFSOutputStream類仿便,用此類來與數(shù)據(jù)節(jié)點(diǎn)與名稱節(jié)點(diǎn)交互。
當(dāng)客戶端寫數(shù)據(jù)的時(shí)候(步驟3),DFSOutputStream首先將數(shù)據(jù)拆分成多個(gè)包攒巍,寫入"數(shù)據(jù)隊(duì)列"中嗽仪。然后,DataStreamer過來消費(fèi)這個(gè)數(shù)據(jù)隊(duì)列窑业,它會(huì)向名稱節(jié)點(diǎn)請(qǐng)求一些合適的新塊用于存儲(chǔ)復(fù)本數(shù)據(jù)钦幔。名稱節(jié)點(diǎn)會(huì)返回包含這些新塊的數(shù)據(jù)節(jié)點(diǎn)列表。這些數(shù)據(jù)節(jié)點(diǎn)形成了一個(gè)通道常柄,這里鲤氢,我們假設(shè)復(fù)制級(jí)別是3搀擂,所以在這個(gè)通道中有三個(gè)節(jié)點(diǎn)。DataStreamer首先向這個(gè)通道中第一個(gè)數(shù)據(jù)節(jié)點(diǎn)寫入之前被拆分的包數(shù)據(jù)卷玉。第一個(gè)數(shù)據(jù)節(jié)點(diǎn)寫完后哨颂,會(huì)前進(jìn)到第二個(gè)數(shù)據(jù)節(jié)點(diǎn),第二個(gè)數(shù)據(jù)節(jié)點(diǎn)存儲(chǔ)包數(shù)據(jù)后繼續(xù)前進(jìn)到第三個(gè)也是最后一個(gè)數(shù)據(jù)節(jié)點(diǎn)(步驟4)相种。
DFSOutStream也會(huì)在內(nèi)部維護(hù)一個(gè)"包隊(duì)列"威恼。只有當(dāng)某一個(gè)包被所有節(jié)點(diǎn)存儲(chǔ)后,這個(gè)包才會(huì)從包隊(duì)列中刪除(步驟5)寝并。
如果在數(shù)據(jù)寫入過程中箫措,任何一個(gè)數(shù)據(jù)節(jié)點(diǎn)寫入失敗了,那么將么執(zhí)行如下操作(這些操作對(duì)客戶端來說是透明的)衬潦。首先斤蔓,通道關(guān)閉,包隊(duì)列中的所有包都將會(huì)放到數(shù)據(jù)隊(duì)列前面镀岛。這樣弦牡,失敗數(shù)據(jù)節(jié)點(diǎn)的下游數(shù)據(jù)節(jié)點(diǎn)不會(huì)錯(cuò)過任何一個(gè)包。在好的數(shù)據(jù)節(jié)點(diǎn)上的當(dāng)前塊被給予一個(gè)新的身份標(biāo)識(shí)漂羊,將它傳送給名稱節(jié)點(diǎn)驾锰,以便以后當(dāng)失敗的數(shù)據(jù)節(jié)點(diǎn)恢復(fù)后,它上面已經(jīng)保存的部分塊數(shù)據(jù)將會(huì)被刪除走越。失敗的數(shù)據(jù)節(jié)點(diǎn)從通道中移除椭豫,再基于剩下兩個(gè)好的數(shù)據(jù)節(jié)點(diǎn)建立一個(gè)新通道。數(shù)據(jù)塊中剩余的數(shù)據(jù)寫到管道中剩下好的數(shù)據(jù)節(jié)點(diǎn)中旨指。名稱節(jié)點(diǎn)知道這個(gè)塊還需要復(fù)制捻悯,所以它會(huì)把它復(fù)制到另外一個(gè)節(jié)點(diǎn)中.余下的塊照常處理。
雖然不太可能淤毛,但在寫入數(shù)據(jù)的時(shí)候仍有可能幾個(gè)數(shù)據(jù)節(jié)點(diǎn)同時(shí)失敗今缚,只要dfs.namenode.replication.min復(fù)本數(shù)(默認(rèn)是1)有值,就會(huì)寫入成功低淡。塊將會(huì)在集群中異步復(fù)制直到達(dá)到設(shè)定的復(fù)本復(fù)制數(shù)(dfs.replication默認(rèn)是3)姓言。
當(dāng)客戶端寫入數(shù)據(jù)完成后喂江,將會(huì)調(diào)用close()方法關(guān)閉流(步驟6)又固。這個(gè)方法將會(huì)清除數(shù)據(jù)節(jié)點(diǎn)通道中剩下的包,并等待所有包數(shù)據(jù)寫入完成缀壤,然后通知名稱節(jié)點(diǎn)猪杭,整個(gè)文件已經(jīng)寫入完成(步驟7)餐塘。名稱節(jié)點(diǎn)知道這個(gè)文件由哪些塊組成(因?yàn)镈ataStreamer是向名稱節(jié)點(diǎn)請(qǐng)求得到塊的位置的),所以它僅需要等待塊完成了最小復(fù)制就可以成功返回了皂吮。
復(fù)本存儲(chǔ)
名稱節(jié)點(diǎn)是怎么知道選擇哪些數(shù)據(jù)節(jié)點(diǎn)存儲(chǔ)復(fù)本呢戒傻?這是在綜合權(quán)衡了可靠性税手,寫入數(shù)據(jù)帶寬和讀取數(shù)據(jù)帶寬之后得到的結(jié)果。例如:如果將所有復(fù)本放在一個(gè)節(jié)點(diǎn)上將會(huì)造成最小的寫入帶寬(因?yàn)閺?fù)制通道運(yùn)行在一個(gè)節(jié)點(diǎn)上)需纳,而且芦倒,這不是真正的冗余,因?yàn)槿绻@個(gè)節(jié)點(diǎn)損壞了不翩,塊數(shù)據(jù)就會(huì)丟失兵扬。但是讀數(shù)據(jù)的帶寬會(huì)很高。另一種極端的情況口蝠,將復(fù)本放在不同的數(shù)據(jù)中心器钟,這樣或許能最大化冗余度,但是卻很消耗帶寬妙蔗。即使在相同的數(shù)據(jù)中心中俱箱,也會(huì)有很多種不同的存儲(chǔ)策略。
一旦復(fù)本的存儲(chǔ)位置確定了秘狞,就會(huì)建立一個(gè)通道,結(jié)合考慮hadoop的網(wǎng)絡(luò)拓?fù)浣Y(jié)構(gòu)之后進(jìn)行數(shù)據(jù)的寫入蹈集。對(duì)于復(fù)本個(gè)數(shù)為3的情況烁试,通道也許如圖3-5所示:
Hadoop默認(rèn)的策略是將第一個(gè)復(fù)本存放在客戶機(jī)所在的節(jié)點(diǎn)中(對(duì)于運(yùn)行在集群外的客戶端來說灭必,將會(huì)隨機(jī)選擇一個(gè)節(jié)點(diǎn),系統(tǒng)盡量不會(huì)選擇已經(jīng)存儲(chǔ)很滿或工作太忙的節(jié)點(diǎn))乃摹。第二個(gè)復(fù)本存儲(chǔ)時(shí)將會(huì)選擇與第一個(gè)節(jié)點(diǎn)不在同一個(gè)硬盤陣列的另外一個(gè)機(jī)架禁漓,隨機(jī)選擇一個(gè)節(jié)點(diǎn)存儲(chǔ)。第三個(gè)復(fù)本將會(huì)放在與第二個(gè)節(jié)點(diǎn)相同的機(jī)架中孵睬,但是存儲(chǔ)在隨機(jī)選擇的另外一個(gè)節(jié)點(diǎn)中播歼。其它的復(fù)本將會(huì)存儲(chǔ)在集群中隨機(jī)選擇的節(jié)點(diǎn)中,系統(tǒng)盡量避免將太量復(fù)本放到相同的機(jī)架中掰读。
圖3-5:一個(gè)典型的復(fù)制通道
總之,這個(gè)策略在可靠性(塊被存儲(chǔ)在兩個(gè)機(jī)架中),寫入帶寬(寫數(shù)據(jù)時(shí)僅需要通過一個(gè)網(wǎng)絡(luò)交換機(jī))拢肆,讀取性能(可以選擇兩個(gè)機(jī)架中任意一個(gè)讀取)减响,塊的分布性(客戶端僅在本地機(jī)架中寫入一個(gè)塊)這些因素之間做了比較好的權(quán)衡。
一致性模型
文件系統(tǒng)的一致性模型描述了讀取文件中的數(shù)據(jù)或向文件寫入數(shù)據(jù)的可見性郭怪。HDFS為了性能犧牲了一些POSIX標(biāo)準(zhǔn)的要求支示,導(dǎo)致一些操作可能與你期望的不一樣。
在創(chuàng)建一個(gè)文件后鄙才,正如所期望的那樣颂鸿,在文件系統(tǒng)名稱空間中看見了這個(gè)文件。
Path p=new Path("p");
fs.create(p);
assertThat(fs.exists(p),is(true));
然而攒庵,任何寫入到這個(gè)文件的數(shù)據(jù)不一定可見嘴纺,即使輸出流被flush刷新了败晴。這個(gè)文件的長度仍為0。
Path p=new Path("p");
OutputStream out=fs.create(p);
out.write("content".getBytes("UTF-8"));
out.flush();
assertThat(fs.getFileStatus(p).getLen(),is(0L));
一旦超過一個(gè)hadoop塊的數(shù)據(jù)寫入了颖医,第一個(gè)塊將對(duì)讀取器可見位衩。對(duì)于后續(xù)的塊也是如此。當(dāng)前正在被寫入數(shù)據(jù)的塊總是對(duì)新來的讀取器不可見熔萧。
HDFS通過FSDataOutputStream的hflush()方法可以強(qiáng)迫緩存中的數(shù)據(jù)flush進(jìn)數(shù)據(jù)節(jié)點(diǎn)糖驴。在hflush()方法成功返回后,HDFS確保已經(jīng)寫入文件的數(shù)據(jù)都存進(jìn)了寫數(shù)據(jù)管道中的數(shù)據(jù)節(jié)點(diǎn)中佛致,并且對(duì)新來的讀取器可見贮缕。
Path p=new Path("p");
FSDataOutputStream out=fs.create(p);
out.write("content".getBytes("UTF-8"));
out.hflush();
assertThat(fs.getFileStatus(p).getLen(),is((long)"contents".length()));
注意hflush()不能確保數(shù)據(jù)節(jié)點(diǎn)已經(jīng)將數(shù)據(jù)寫入磁盤中,僅僅確保數(shù)據(jù)存儲(chǔ)在數(shù)據(jù)節(jié)點(diǎn)的內(nèi)存中(所以如果數(shù)據(jù)中心斷電了俺榆,數(shù)據(jù)將會(huì)丟失)感昼。如果需要確保數(shù)據(jù)能寫入磁盤,請(qǐng)使用hsync()罐脊。
hsync()方法內(nèi)部的操作與POSIX標(biāo)準(zhǔn)中fsync()標(biāo)準(zhǔn)命令相似定嗓,都會(huì)提交緩存中的數(shù)據(jù)到磁盤。例如萍桌,使用標(biāo)準(zhǔn)的JAVA API將數(shù)據(jù)寫入本地文件宵溅,在flush數(shù)據(jù)流和同步數(shù)據(jù)到磁盤后,就可以確保能看見已經(jīng)寫入文件的內(nèi)容上炎。
FileOutputStream out=new FileOutputStream(localFile);
out.write("contents".getBytes("UTF-8"));
out.flush();//flush操作系統(tǒng)
out.getFD().sync();//同步進(jìn)磁盤
assertThat(localFile.length(),is((long)"contents".length()));
關(guān)閉HDFS的文件流時(shí)內(nèi)部也會(huì)執(zhí)行hflush()方法恃逻。
Path p=new Path("p");
OutputStream out=fs.create(p);
out.write("contents".getBytes("UTF-8"));
out.close();
assertThat(fs.getFileStatus().getLen(),is((long)"contents".length()));
應(yīng)用設(shè)計(jì)的重要性
一致性模型已經(jīng)蘊(yùn)涵了設(shè)計(jì)應(yīng)用的方法。如果不調(diào)用hflush()和hsync()藕施,當(dāng)客戶端或系統(tǒng)故障時(shí)寇损,你將會(huì)丟失大量數(shù)據(jù)。對(duì)很多應(yīng)用來說裳食,這是不可接受的矛市。所以你應(yīng)該在合適的時(shí)機(jī)調(diào)用hflush(),例如在寫入相當(dāng)一部分?jǐn)?shù)據(jù)記錄或字節(jié)之后诲祸。雖然hflush()這個(gè)方法在設(shè)計(jì)時(shí)考慮到不對(duì)HDFS造成太大負(fù)擔(dān)尘盼,但是它確實(shí)對(duì)性能有一些影響(hsync()有更多影響)。所以在數(shù)據(jù)健壯性與傳輸率之間要有一個(gè)權(quán)衡烦绳。一個(gè)可接受的平衡點(diǎn)是當(dāng)以不同頻率調(diào)用hflush()卿捎,并在考量應(yīng)用性能前提下,那些依賴應(yīng)用径密,合適的數(shù)據(jù)都能被讀取到時(shí)午阵。
使用distcp并發(fā)復(fù)制
到目前為止我們看到的HDFS獲取數(shù)據(jù)的形式都是單線程的。例如,通過指定文件通配符的方法底桂,我們可以同時(shí)操作大量文件植袍。但要想有效地并發(fā)處理這些文件 ,你必須自己編程籽懦。Hadoop提供了一個(gè)有用的程序于个,叫做distcp,用于并發(fā)地將數(shù)據(jù)復(fù)制到hadoop或從Hadoop復(fù)制數(shù)據(jù)暮顺。
distcp其中的一個(gè)用途是替代hadoop fs -cp命令厅篓。例如,你可以復(fù)制一個(gè)文件到另一個(gè)文件中通過使用
% hadoop distcp file1 file2
你也可以復(fù)制目錄:
% hadoop distcp dir1 dir2
如果目錄dir2不存在捶码,hadoop將會(huì)創(chuàng)建它羽氮。并且目錄1中的內(nèi)容將復(fù)制到目錄dir2中。你可以指定多個(gè)源路徑惫恼,所有這些源路徑下的文件都將會(huì)復(fù)制到目的目錄中档押。
如果目錄dir2已經(jīng)存在了,dir1目錄將復(fù)制到它下一級(jí)祈纯,創(chuàng)建目錄結(jié)構(gòu)dir2/dir1令宿。如果這不是你所想要的,你可以通過使用-overwrite選項(xiàng)腕窥,將數(shù)據(jù)以覆蓋的形式復(fù)制到dir2目錄下粒没。你也可以只更新那些已經(jīng)改變的文件,使用-update選項(xiàng)油昂。我們通過一個(gè)示例說明。如果我們?cè)谀夸沝ir1中修改了一個(gè)文件倾贰,我們將會(huì)使用如下命令將dir1目錄的修改同步進(jìn)dir2中冕碟。
% hadoop distcp -update dir1 dir2
distcp使用MapReduce作業(yè)方式實(shí)現(xiàn),在集群中并發(fā)運(yùn)行多個(gè)map來進(jìn)行復(fù)制工作匆浙,沒有reducer安寺。每一個(gè)file使用一個(gè)map復(fù)制。Distcp粗略地將所有文件等分成幾份首尼,以便給每一個(gè)map分配近似相等的數(shù)據(jù)量挑庶。默認(rèn)情況下,最多使用20個(gè)map软能。但是這個(gè)值可以通過在distcp中指定-m參數(shù)改變迎捺。
使用distcp一個(gè)非常常用的用途是在兩個(gè)HDFS集群間傳輸數(shù)據(jù)。例如查排,下面命令在第二個(gè)集群中創(chuàng)建了第一個(gè)集群/foo目錄下文件的備份凳枝。
% hadoop distcp -update -delete -p hdfs://namenode1/foo hdfs://namenod2/foo
-delete參數(shù)使用distcp刪除目的目錄下有而源目錄沒有的文件或目錄。-p參數(shù)意思是文件的狀態(tài)屬性像權(quán)限,塊大小和復(fù)本個(gè)數(shù)都保留岖瑰。你可以不帶任何參數(shù)運(yùn)行distcp命令來查看參數(shù)的詳細(xì)使用說明叛买。
如果這兩個(gè)集群運(yùn)行不同版本的HDFS,那么你可以使用webhdfs協(xié)議在兩個(gè)集群間復(fù)制蹋订。
% hadoop distcp webhdfs://namenode1:50070/foo webhdfs://namenode2:50070/foo
另一種變通的方法可以使用HTTPFS代理做為distcp的源或目的地(它也使用了webhdfs協(xié)議率挣,可以設(shè)置防火墻和控制帶寬,參看"HTTP章節(jié)")露戒。
保持HDFS集群平衡
當(dāng)將數(shù)據(jù)復(fù)制到HDFS中時(shí)椒功,考慮集群的平衡性很重要。當(dāng)文件塊在集群中均勻連續(xù)存儲(chǔ)時(shí)玫锋,HDFS能夠表現(xiàn)地最好蛾茉。所以你使用distcp時(shí)也要確保不打破這個(gè)規(guī)則。例如撩鹿,如果你如果指定-m 1,將會(huì)有一個(gè)map進(jìn)行復(fù)制工作谦炬,先不考慮這樣做效率很低,沒有充分有效地利用集群資源节沦,這樣做就意味著每一個(gè)塊的第一個(gè)復(fù)本將位于運(yùn)行map任務(wù)的節(jié)點(diǎn)上(直到磁盤滿了)键思。第二個(gè)和第三個(gè)復(fù)本將會(huì)在集群其它節(jié)點(diǎn)上。但是這樣就達(dá)不到平衡甫贯,如果使集群中map任務(wù)數(shù)比節(jié)點(diǎn)數(shù)多吼鳞,就可以避免這個(gè)問題。所以叫搁,當(dāng)運(yùn)行distcp命令時(shí)赔桌,最好使用默認(rèn)的每一個(gè)節(jié)點(diǎn)20個(gè)map任務(wù)。
然而渴逻,不可能一直保持集群平衡疾党。也許你想要限制map任務(wù)的個(gè)數(shù),以便節(jié)點(diǎn)上資源能夠被其它作業(yè)使用惨奕。這種情況下雪位,你可以使用平衡工具(可參看"平衡器章節(jié)")使集群中的塊分布地更加均衡。
本文是筆者翻譯自《OReilly.Hadoop.The.Definitive.Guide.4th.Edition》第一部分第3章梨撞,后續(xù)將繼續(xù)翻譯其它章節(jié)雹洗。雖盡力翻譯,但奈何水平有限卧波,錯(cuò)誤再所難免时肿,如果有問題,請(qǐng)不吝指出港粱!希望本文對(duì)你有所幫助嗜侮。