DistCp(分散式複製)是一個用於大型叢集間/叢集內複製的工具。它使用 MapReduce 來執行其分發、錯誤處理和復原,以及報告。它將檔案和目錄清單擴充為映射任務的輸入,每個任務將複製來源清單中指定檔案的一個分割區。
[DistCp 的前身實作] (https://hadoop.dev.org.tw/docs/r1.2.1/distcp.html) 在其用法、可擴充性和效能方面都有其怪癖和缺點。DistCp 重構的目的是修正這些缺點,使其能夠以程式化方式使用和擴充。已引入新的範例來改善執行時間和設定效能,同時保留舊有行為作為預設。
本文檔旨在描述新 DistCp 的設計、其嶄新的功能、其最佳使用方式,以及與舊有實作的任何差異。
DistCp 最常見的呼叫是叢集間複製
bash$ hadoop distcp hdfs://nn1:8020/foo/bar \ hdfs://nn2:8020/bar/foo
這將把 nn1 上 /foo/bar
下的命名空間擴充到一個暫存檔中,將其內容分割到一組映射任務中,並在每個 NodeManager 上從 nn1
到 nn2
開始複製。
您還可以在命令列上指定多個來源目錄
bash$ hadoop distcp hdfs://nn1:8020/foo/a \ hdfs://nn1:8020/foo/b \ hdfs://nn2:8020/bar/foo
或者,等效地,從使用 -f 選項的檔案
bash$ hadoop distcp -f hdfs://nn1:8020/srclist \ hdfs://nn2:8020/bar/foo
其中 srclist
包含
hdfs://nn1:8020/foo/a hdfs://nn1:8020/foo/b
從多個來源複製時,如果兩個來源發生衝突,DistCp 會中止複製並顯示錯誤訊息,但會根據指定的 選項 解決目標端的衝突。預設情況下,會略過目標端已存在的檔案(即不會以來源檔案取代)。每個工作結束時會報告略過的檔案數量,但如果複製器對某些檔案子集失敗,但在後續嘗試中成功,則報告可能不準確。
每個 NodeManager 都能連線並與來源和目標檔案系統通訊非常重要。對於 HDFS,來源和目標都必須執行相同版本的通訊協定,或使用向下相容的通訊協定;請參閱 [不同 HDFS 版本之間的複製] (#Copying_Between_Versions_of_HDFS)。
複製後,建議產生來源和目標的清單並進行交叉比對,以驗證複製是否真的成功。由於 DistCp 同時使用 Map/Reduce 和 FileSystem API,因此這三者之間或其中的任何問題都可能對複製造成負面且無聲的影響。有些人成功執行啟用 -update
的操作,以執行第二次傳遞,但使用者在嘗試此操作之前應先了解其語意。
另外值得注意的是,如果其他用戶端仍在寫入來源檔案,則複製可能會失敗。嘗試覆寫在目標端寫入的檔案也應該會在 HDFS 上失敗。如果來源檔案在複製之前被(重新)移除,則複製會失敗並顯示 FileNotFoundException
。
請參閱詳細的命令列參考,以取得 DistCp 中所有可用選項的資訊。
-update
用於複製目標端不存在或與目標版本不同的來源檔案。-overwrite
會覆寫目標端存在的目標檔案。
更新和覆寫選項需要特別注意,因為它們處理來源路徑的方式與預設值有非常細微的不同。考慮從 /source/first/
和 /source/second/
複製到 /target/
,其中來源路徑包含下列內容
hdfs://nn1:8020/source/first/1 hdfs://nn1:8020/source/first/2 hdfs://nn1:8020/source/second/10 hdfs://nn1:8020/source/second/20
當未在 DistCp 中呼叫 -update
或 -overwrite
時,DistCp 預設會在 /target
下建立目錄 first/
和 second/
。因此
distcp hdfs://nn1:8020/source/first hdfs://nn1:8020/source/second hdfs://nn2:8020/target
會在 /target
中產生下列內容
hdfs://nn2:8020/target/first/1 hdfs://nn2:8020/target/first/2 hdfs://nn2:8020/target/second/10 hdfs://nn2:8020/target/second/20
當指定 -update
或 -overwrite
時,會將來源目錄的內容複製到目標,而非來源目錄本身。因此
distcp -update hdfs://nn1:8020/source/first hdfs://nn1:8020/source/second hdfs://nn2:8020/target
會在 /target
中產生下列內容
hdfs://nn2:8020/target/1 hdfs://nn2:8020/target/2 hdfs://nn2:8020/target/10 hdfs://nn2:8020/target/20
進一步延伸,如果兩個來源資料夾都包含同名的檔案(例如 0
),則兩個來源都會將一個項目對應到目的地的 /target/0
。DistCp 會中止,而不是允許此衝突發生。
現在,考慮下列複製作業
distcp hdfs://nn1:8020/source/first hdfs://nn1:8020/source/second hdfs://nn2:8020/target
來源/大小
hdfs://nn1:8020/source/first/1 32 hdfs://nn1:8020/source/first/2 32 hdfs://nn1:8020/source/second/10 64 hdfs://nn1:8020/source/second/20 32
目標/大小
hdfs://nn2:8020/target/1 32 hdfs://nn2:8020/target/10 32 hdfs://nn2:8020/target/20 64
將會影響
hdfs://nn2:8020/target/1 32 hdfs://nn2:8020/target/2 32 hdfs://nn2:8020/target/10 64 hdfs://nn2:8020/target/20 32
略過 1
,因為檔案長度和內容相符。複製 2
,因為它不存在於目標中。覆寫 10
和 20
,因為內容與來源不符。
如果使用 -update
,則會略過 1
,因為檔案長度和內容相符。複製 2
,因為它不存在於目標中。覆寫 10
和 20
,因為內容與來源不符。但是,如果另外使用 -append
,則只會覆寫 10
(來源長度小於目標)並將檔案變更附加到 20
(如果檔案與目標的原始長度相符)。
如果使用 -overwrite
,則也會覆寫 1
。
-diff
選項會使用快照差異從來源叢集同步檔案到目標叢集。它會複製、重新命名和移除快照差異清單中的檔案。
使用 -diff
選項時,必須包含 -update
選項。
目前,大多數雲端供應商無法順利地進行同步。
用法
hadoop distcp -update -diff <from_snapshot> <to_snapshot> <source> <destination>
範例
hadoop distcp -update -diff snap1 snap2 /src/ /dst/
上述指令會將快照 snap1
至 snap2
的變更(即從 snap1
至 snap2
的快照差異)套用在 /src/
至 /dst/
。顯然,它需要 /src/
同時具有快照 snap1
和 snap2
。但是,目標 /dst/
也必須具有與 <from_snapshot>
同名的快照,在本例中為 snap1
。目標 /dst/
自 snap1
以來不應有新的檔案作業(建立、重新命名、刪除)。請注意,當此指令完成時,不會在 /dst/
建立新的快照 snap2
。
使用 -diff
選項需要 -update
。
例如,如果在 /src/
中,在建立 snap1
之後和建立 snap2
之前,新增了 1.txt
並刪除了 2.txt
,則上述指令會將 1.txt
從 /src/
複製到 /dst/
,並從 /dst/
刪除 2.txt
。
同步行為將使用以下實驗進行說明。
開始前的一些準備工作。
# Create source and destination directories hdfs dfs -mkdir /src/ /dst/ # Allow snapshot on source hdfs dfsadmin -allowSnapshot /src/ # Create a snapshot (empty one) hdfs dfs -createSnapshot /src/ snap1 # Allow snapshot on destination hdfs dfsadmin -allowSnapshot /dst/ # Create a from_snapshot with the same name hdfs dfs -createSnapshot /dst/ snap1 # Put one text file under /src/ echo "This is the 1st text file." > 1.txt hdfs dfs -put 1.txt /src/ # Create the second snapshot hdfs dfs -createSnapshot /src/ snap2 # Put another text file under /src/ echo "This is the 2nd text file." > 2.txt hdfs dfs -put 2.txt /src/ # Create the third snapshot hdfs dfs -createSnapshot /src/ snap3
然後執行 distcp 同步
hadoop distcp -update -diff snap1 snap2 /src/ /dst/
上述命令應會成功。1.txt
將從 /src/
複製到 /dst/
。同樣地,需要 -update
選項。
如果我們再次執行相同的命令,我們將會收到 DistCp sync failed
例外,因為自 snap1
以來,目的地已新增一個新檔案 1.txt
。話雖如此,如果我們手動從 /dst/
中移除 1.txt
並執行同步,命令將會成功。
首先從實驗 1 進行清理。
hdfs dfs -rm -skipTrash /dst/1.txt
執行同步命令,請注意 <to_snapshot>
已從實驗 1 中的 snap2
變更為 snap3
。
hadoop distcp -update -diff snap1 snap3 /src/ /dst/
1.txt
和 2.txt
都將複製到 /dst/
。
從實驗 2 的結尾繼續
hdfs dfs -rm -skipTrash /dst/2.txt # Create snap2 at destination, it contains 1.txt hdfs dfs -createSnapshot /dst/ snap2 # Delete 1.txt from source hdfs dfs -rm -skipTrash /src/1.txt # Create snap4 at source, it only contains 2.txt hdfs dfs -createSnapshot /src/ snap4
現在執行同步命令
hadoop distcp -update -diff snap2 snap4 /src/ /dst/
2.txt
已複製,1.txt
已在 /dst/
中刪除。
請注意,儘管 /src/
和 /dst/
都具有名稱相同的快照 snap2
,但快照不需要具有相同的內容。這表示,如果在 /dst/
的 snap2
中有 1.txt
,但它們的內容不同,1.txt
仍將從 /dst/
中移除。同步命令不會檢查將要刪除的檔案的內容。它僅遵循 <from_snapshot>
和 <to_snapshot>
之間的快照差異清單。
此外,如果我們在上述步驟中建立 /dst/
上的 snap2
之前從 /dst/
中刪除 1.txt
,以便 /dst/
的 snap2
在執行同步命令之前沒有 1.txt
,命令仍將成功。它不會在嘗試從不存在的 /dst/
中刪除 1.txt
時擲回例外。
此區段僅適用於 HDFS。
如果目標和所有來源路徑名稱都在 /.reserved/raw
層級結構中,則會保留「原始」命名空間延伸屬性。「原始」xattr 由系統用於內部功能,例如加密元資料。只有透過 /.reserved/raw
層級結構存取時,使用者才能看到它們。
原始 xattrs 的保留僅基於是否提供 /.reserved/raw 前綴。-p (保留,見下文) 標記不會影響原始 xattrs 的保留。
若要防止保留原始 xattrs,只需在任何來源和目標路徑上不使用 /.reserved/raw
前綴。
如果僅在來源和目標路徑的子集上指定 /.reserved/raw
前綴,將會顯示錯誤並傳回非 0 退出代碼。
標記 | 說明 | 備註 |
---|---|---|
-p[rbugpcaxt] |
保留 r:複製次數 b:區塊大小 u:使用者 g:群組 p:權限 c:檢查碼類型 a:ACL x:XAttr t:時間戳記 | 當指定 -update 時,除非檔案大小也有所不同(即除非重新建立檔案),否則狀態更新將不會同步。如果指定 -pa,DistCp 也會保留權限,因為 ACL 是權限的超集。選項 -pr 僅在來源和目標目錄均未進行刪除編碼時才有效。 |
-i |
忽略失敗 | 如附錄中所述,此選項將保留比預設情況更準確的複製統計資料。它也會保留失敗複製的記錄,這對於除錯很有價值。最後,失敗的對應不會導致工作在嘗試所有分割之前就失敗。 |
-log <logdir> |
將記錄寫入 <logdir> | DistCp 會將其嘗試複製的每個檔案的記錄保留為對應輸出。如果對應失敗,則在重新執行時不會保留記錄輸出。 |
-v |
在 SKIP/COPY 記錄中記錄額外資訊(路徑、大小) | 此選項只能與 -log 選項一起使用。 |
-m <num_maps> |
同時複製的最大數量 | 指定複製資料的對應數量。請注意,更多的對應不一定會改善傳輸量。 |
-overwrite |
覆寫目的地 | 如果對應失敗且未指定 -i ,則會重新複製分割中的所有檔案,而不僅僅是失敗的檔案。如使用說明檔中所述,它也會變更產生目的地路徑的語意,因此使用者應小心使用。 |
-update |
如果來源和目的地在大小、區塊大小或檢查碼上不同,則覆寫 | 如前所述,這不是「同步」操作。檢查的條件是來源和目的地檔案大小、區塊大小和檢查碼;如果不同,來源檔案會取代目的地檔案。如使用說明文件中所述,它也會變更產生目的地路徑的語意,因此使用者應謹慎使用。 |
-append |
具有相同名稱但不同長度的檔案的增量複製 | 如果來源檔案長度大於目的地檔案,則會比較共用長度部分的檢查碼。如果檢查碼相符,則只會使用讀取和附加功能複製差異。-append 選項僅與 -update 搭配使用,且不使用 -skipcrccheck |
-f <urilist_uri> |
使用 <urilist_uri> 中的清單作為來源清單 | 這等於在命令列中列出每個來源。urilist_uri 清單應為完全限定的 URI。 |
-filters |
包含模式字串清單檔案的路徑,每行一個字串,符合該模式的路徑將從複製中排除。 | 支援由 java.util.regex.Pattern 指定的正規表示式。 |
-filelimit <n> |
將檔案總數限制為 <= n | 已棄用!新 DistCp 中會忽略。 |
-sizelimit <n> |
將總大小限制為 <= n 位元組 | 已棄用!新 DistCp 中會忽略。 |
-delete |
刪除存在於目的地但不存在於來源的檔案 | 刪除是由 FS Shell 執行。因此,如果啟用,將會使用垃圾桶。刪除僅適用於更新或覆寫選項。 |
-strategy {dynamic|uniformsize} |
選擇要在 DistCp 中使用的複製策略。 | 預設使用 uniformsize。(即,根據每個映射複製的檔案總大小來平衡映射。類似於舊版。)如果指定「dynamic」,則會改用 DynamicInputFormat 。(這在架構區段的 InputFormats 中有說明。) |
-bandwidth |
以 MB/秒指定每個映射的頻寬。 | 每個映射將被限制僅使用指定的頻寬。這並不總是精確的。映射會在複製期間降低其頻寬使用量,使得使用的淨頻寬趨向於指定的值。 |
-atomic {-tmp <tmp_dir>} |
指定原子提交,並可選擇暫存目錄。 | -atomic 指示 DistCp 將來源資料複製到暫時目標位置,然後將暫時目標原子性地移至最終位置。資料將以完整且一致的形式出現在最終目標,或根本不會出現。選擇性地,-tmp 可用於指定暫時目標的位置。如果未指定,將選擇預設值。注意:tmp_dir 必須在最終目標叢集上。 |
-async |
非同步執行 DistCp。在 Hadoop 工作啟動後立即退出。 | 已記錄 Hadoop 工作識別碼,以進行追蹤。 |
-diff <oldSnapshot> <newSnapshot> |
使用兩個快照之間的快照差異報告,找出來源和目標之間的差異,並套用差異到目標,使其與來源同步。 | 此選項僅與 -update 選項有效,且應符合下列條件。
|
-rdiff <newSnapshot> <oldSnapshot> |
使用兩個快照之間的快照差異報告,找出自快照 <oldSnapshot> 建立在目標上以來,目標上已變更的內容,並反向套用差異到目標,並從來源的 <oldSnapshot> 複製已修改的檔案,使目標與 <oldSnapshot> 相同。 |
此選項僅與 -update 選項有效,且應符合下列條件。
|
-numListstatusThreads |
用於建立檔案清單的執行緒數目 | 最多 40 個執行緒。 |
-skipcrccheck |
是否略過來源和目標路徑之間的 CRC 檢查。 | |
-blocksperchunk <blocksperchunk> |
每個區塊的區塊數目。指定時,將檔案分割成區塊以平行複製 | 如果設定為正值,區塊數目多於此值的檔案將分割成 <blocksperchunk> 個區塊,以便平行傳輸,並在目的地重新組合。預設情況下,<blocksperchunk> 為 0,檔案將完整傳輸而不分割。此開關僅適用於來源檔案系統實作 getBlockLocations 方法,且目標檔案系統實作 concat 方法時。 |
-copybuffersize <copybuffersize> |
要使用的複製緩衝區大小。預設情況下,<copybuffersize> 設定為 8192B |
|
-xtrack <path> |
將遺失來源檔案的資訊儲存到指定的路徑。 | 此選項僅與 -update 選項有效。這是實驗性質,且無法與 -atomic 選項搭配使用。 |
-direct |
直接寫入目的地路徑 | 當目的地為物件儲存時,可避免潛在耗時的暫時檔案重新命名作業,因此很有用 |
-useiterator |
使用單執行緒 listStatusIterator 建立清單 | 可節省用戶端的記憶體。使用此選項將忽略 numListstatusThreads 選項 |
新 DistCp 的元件可分類為下列類別
DistCp 驅動程式元件負責
透過
分析傳遞至命令列上 DistCp 命令的引數,並將命令引數組裝成適當的 DistCpOptions 物件,並初始化 DistCp。這些引數包括
透過
剖析器元素僅從命令列(或呼叫 DistCp::run() 時)執行。DistCp 類別也可以透過建構 DistCpOptions 物件和適當地初始化 DistCp 物件,以程式方式使用。
複製清單產生器類別負責建立要從來源複製的檔案/目錄清單。它們會檢查來源路徑的內容(包括萬用字元),並將所有需要複製的路徑記錄到 SequenceFile 中,供 DistCp Hadoop 作業使用。此模組中的主要類別包括
CopyListing
:任何複製清單產生器實作都應實作的介面。也提供具體 CopyListing 實作的選擇方式的工廠方法。SimpleCopyListing
:CopyListing
的實作,接受多個來源路徑(檔案/目錄),並遞迴列出每個路徑下的所有個別檔案和目錄,以供複製。GlobbedCopyListing
:CopyListing
的另一個實作,會在來源路徑中展開萬用字元。FileBasedCopyListing
:CopyListing
的實作,從指定檔案中讀取來源路徑清單。根據 DistCpOptions 中是否指定來源檔案清單,來源清單會以下列其中一種方式產生
GlobbedCopyListing
。會展開所有萬用字元,並將所有展開項目轉送至 SimpleCopyListing,而 SimpleCopyListing 會建構清單(透過遞迴每個路徑)。FileBasedCopyListing
。來源路徑會從指定檔案中讀取,然後轉送至 GlobbedCopyListing
。然後如上所述建構清單。可以透過提供 CopyListing 介面的自訂實作,自訂建構複製清單的方法。DistCp 在這裡的行為與舊版 DistCp 不同,在於路徑如何考量複製。
也可以透過傳遞 CopyFilter 介面的目前支援實作或撰寫新的實作,自訂不應複製的檔案篩選。這可以透過在 DistCpOptions 中設定 distcp.filters.class
來指定
distcp.filters.class
為 “RegexCopyFilter”。如果您使用此實作,則必須傳遞包含用於篩選的正規表示式的 “CopyFilter” distcp.filters.file
。支援 java.util.regex.Pattern 指定的正規表示式。distcp.filters.class
為 “RegexpInConfigurationFilter”。如果您使用此實作,則必須使用 “DistCpOptions” 中的 distcp.exclude-file-regex
參數傳遞正規表示式。支援 java.util.regex.Pattern 指定的正規表示式。與 “RegexCopyFilter” 相比,這是一種更動態的方法。distcp.filters.class
為 “TrueCopyFilter”。如果未指定上述任何選項,則此選項會用作預設實作。舊版實作只會列出必須複製到目標的路徑。例如,如果檔案已存在於目標(且未指定 -overwrite
),則檔案甚至不會在 MapReduce 複製工作中考慮。在設定期間(即在 MapReduce 工作之前)確定這一點,涉及檔案大小和檢查總和比較,這可能會耗時。
新的 DistCp 會將此類檢查延後到 MapReduce 工作,從而減少設定時間。由於這些檢查會在多個映射中並行處理,因此效能會進一步提升。
InputFormats 和 MapReduce 元件負責實際將檔案和目錄從來源複製到目的地路徑。在執行複製時,會使用在複製清單產生期間建立的清單檔案。這裡感興趣的類別包括
UniformSizeInputFormat:此 org.apache.hadoop.mapreduce.InputFormat 實作提供與 Legacy DistCp 相同的負載平衡功能,讓各個映射處理的資料量大致相同。UniformSizeInputFormat 的目標是讓每個映射複製的位元組數目大致相同。因此,清單檔案會分割成多個路徑群組,讓每個 InputSplit 中檔案大小的總和大致等於其他映射。分割並非總是完美,但其簡單的實作可將設定時間維持在低水準。
DynamicInputFormat 和 DynamicRecordReader:DynamicInputFormat 實作 org.apache.hadoop.mapreduce.InputFormat
,是 DistCp 的新增功能。清單檔案會分割成多個「區塊檔案」,區塊檔案的數量會是 Hadoop 工作中要求的映射數目的倍數。在啟動工作之前,會將每個映射工作「指定」給其中一個區塊檔案(方法是將區塊重新命名為工作的 ID)。會使用 DynamicRecordReader
從每個區塊讀取路徑,並在 CopyMapper 中處理。處理完區塊中的所有路徑後,會刪除目前的區塊並取得新的區塊。此程序會持續進行,直到沒有更多區塊可用為止。這種「動態」方法讓速度較快的映射工作可以比速度較慢的工作處理更多路徑,進而加速整體 DistCp 工作。
CopyMapper:此類別實作實體檔案複製。會將輸入路徑與輸入選項(在工作的設定中指定)進行比對,以判斷是否需要複製檔案。只有符合下列其中一個條件時,才會複製檔案
-skipcrccheck
。-overwrite
。CopyCommitter:此類別負責 DistCp 工作的提交階段,包括
預設情況下,DistCp 會嘗試調整每個映射的大小,讓每個映射複製的位元組數目大致相同。請注意,檔案是細微程度最高的層級,因此增加同時複製的數量(即映射)並不一定會增加同時複製的數量或整體處理量。
新的 DistCp 也提供一種「動態」調整映射大小的策略,讓速度較快的資料節點可以複製比速度較慢的節點更多的位元組。使用 -strategy dynamic
(在架構中說明),而非將一組固定的來源檔案指定給每個映射工作,而是將檔案分割成多組。組數會超過映射數目,通常是 2-3 倍。每個映射會選取並複製區塊中列出的所有檔案。當區塊用盡時,會取得並處理新的區塊,直到沒有更多區塊為止。
不將來源路徑指定給固定映射,速度較快的映射工作(即資料節點)就能夠使用更多區塊,因此比速度較慢的節點複製更多資料。雖然這種分配並不均勻,但考量到每個映射器的容量,這種分配是公平的。
動態策略是由 DynamicInputFormat
實作。在大部分情況下,它都能提供優異的效能。
建議針對來源和目的地叢集的大小、複製的大小,以及可用的頻寬調整映射數目,以執行長時間執行和定期執行的作業。
要在兩個不同主要版本的 Hadoop 之間複製(例如,在 1.X 和 2.X 之間),通常會使用 WebHdfsFileSystem。與先前的 HftpFileSystem 不同,由於 webhdfs 可用於讀取和寫入作業,因此可以在來源和目的地叢集上執行 DistCp。遠端叢集指定為 webhdfs://<namenode_hostname>:<http_port>
。在 Hadoop 叢集的相同主要版本之間複製時(例如,在 2.X 和 2.X 之間),請使用 hdfs 協定以獲得更好的效能。
當 webhdfs 使用 SSL 保護時,請使用「swebhdfs://
」架構。如需更多資訊,請參閱 SWebHDFS 的 SSL 組態。
如前所述,如果映射無法複製其輸入之一,將會產生多個副作用。
-overwrite
,否則在重新執行時,先前映射成功複製的檔案將標記為「已略過」。mapreduce.map.maxattempts
次,將會終止其餘的映射工作(除非設定 -i
)。mapreduce.map.speculative
為最終和 true,則複製結果未定義。DistCp 可與物件儲存(例如 Amazon S3、Azure ABFS 和 Google GCS)搭配使用。
先決條件
DistCp 可用於上傳資料
hadoop distcp -direct hdfs://nn1:8020/datasets/set1 s3a://bucket/datasets/set1
下載資料
hadoop distcp s3a://bucket/generated/results hdfs://nn1:8020/results
在物件儲存之間複製資料
hadoop distcp s3a://bucket/generated/results \ wasb://updates@example.blob.core.windows.net
以及在物件儲存內複製資料
hadoop distcp wasb://updates@example.blob.core.windows.net/current \ wasb://updates@example.blob.core.windows.net/old
並使用 -update
僅複製已變更的檔案。
hadoop distcp -update -numListstatusThreads 20 \ s3a://history/2016 \ hdfs://nn1:8020/history/2016
由於物件儲存列出檔案的速度較慢,因此請考慮在對大型目錄樹執行 -update
作業時設定 -numListstatusThreads
選項(限制為 40 個執行緒)。
當 DistCp -update
與物件儲存體搭配使用時,一般而言只會比較個別檔案的修改時間與長度,不會比較任何檢查碼,如果兩個儲存體之間的檢查碼演算法不同。
具有不同檢查碼演算法的兩個物件儲存體之間的 distcp -update
會比較來源和目標檔案的修改時間以及檔案大小,以判斷是否略過檔案複製。此行為由屬性 distcp.update.modification.time
控制,預設設為 true。如果來源檔案比目標檔案最近修改,則假設內容已變更,且應更新檔案。我們需要確保機器之間沒有時鐘偏移。大多數物件儲存體確實具有目錄的有效時間戳記,這點無關緊要;只會比較檔案時間戳記。不過,重要的是讓用戶端電腦的時鐘接近基礎架構的時鐘,以便用戶端/HDFS 集群與物件儲存體之間的時間戳記一致。否則,變更的檔案可能會被遺漏/過於頻繁地複製。
distcp.update.modification.time
僅會在兩個儲存體都沒有檢查碼驗證,導致兩個儲存體之間的檢查碼比較不相容時使用。即使將屬性設為 true,如果兩個儲存體之間有有效的檢查碼比較,也不會使用它。
若要關閉修改時間檢查,請在 core-site.xml 中設定這項設定
<property> <name>distcp.update.modification.time</name> <value>false</value> </property>
備註
-atomic
選項會導致暫時資料重新命名,因此會大幅增加作業結束時提交工作的時間。此外,由於除了 (選擇性的) wasb://
以外的物件儲存體不提供目錄的原子重新命名,因此 -atomic
作業實際上並未提供所承諾的內容。避免使用。
不支援 -append
選項。
不支援 -diff
和 rdiff
選項
無論 -skipCrc
標記的值為何,都不會執行 CRC 檢查。
一般而言,所有 -p
選項(包括保留權限、使用者和群組資訊、屬性檢查碼和複製)都會被忽略。wasb://
連接器會保留資訊,但不會強制執行權限。
有些物件儲存體連接器提供輸出記憶體內暫存的選項,例如 S3A 連接器。在複製大型檔案時使用此選項可能會觸發某種形式的記憶體不足事件,可能是堆疊溢位或 YARN 容器終止。如果叢集和物件儲存體之間的網路頻寬有限(例如在使用遠端物件儲存體時),這種情況特別常見。最好停用/避免此類選項,並依賴磁碟暫存。
單一物件儲存體內的複製作業仍會在 Hadoop 群集中進行,即使物件儲存體內部實作更有效率的 COPY 作業
也就是說,例如以下作業
hadoop distcp s3a://bucket/datasets/set1 s3a://bucket/datasets/set2
會將每個位元組複製到 Hadoop 工作節點,然後再複製回儲存區。除了速度慢之外,這表示可能會產生費用。
可以使用 -direct
選項直接寫入物件儲存體目標路徑,避免可能非常耗時的暫時性檔案重新命名作業,否則會發生此類作業。
為什麼 -update 沒有在預先存在的目標目錄下建立父來源目錄? -update
和 -overwrite
的行為已在本文件的「使用」區段中詳細說明。簡而言之,如果將任一選項與預先存在的目標目錄搭配使用,則會複製每個來源目錄的內容,而不是來源目錄本身。此行為也與舊版 DistCp 實作一致。
新的 DistCp 在語意上與舊版 DistCp 有何不同?
為什麼新的 DistCp 使用的對應比舊版 DistCp 多? 舊版 DistCp 的運作方式是,在啟動複製工作之前找出實際需要複製到目標的檔案,然後啟動複製所需的對應數量。因此,如果需要略過大部分檔案(例如,因為它們已存在),則需要的對應數量會較少。因此,設定時間(即在 M/R 工作之前)會較長。新的 DistCp 只會計算來源路徑的內容。它不會嘗試篩選出可以略過的檔案。此決定會延後到執行 M/R 工作時才做。這樣會快很多(相對於執行時間),但啟動的對應數量會如 -m
選項中指定,或在未指定時為 20(預設值)。
為什麼在指定更多對應時,DistCp 沒有執行得更快? 目前,DistCp 的最小工作單位是檔案。也就是說,只會有一個對應處理一個檔案。將對應數量增加到超過檔案數量,並不會帶來效能上的好處。啟動的對應數量會等於檔案數量。
為什麼 DistCp 會用完記憶體?如果從來源路徑複製的個別檔案/目錄數量極為龐大(例如 1,000,000 個路徑),DistCp 在決定要複製的路徑清單時可能會用完記憶體。這並非新 DistCp 實作獨有的問題。為了解決此問題,請考慮變更 -Xmx
JVM 堆積大小參數,如下所示
bash$ export HADOOP_CLIENT_OPTS="-Xms64m -Xmx1024m" bash$ hadoop distcp /source /target