MaxCompute 是阿裡巴巴自研的旗艦大資料倉庫服務,與開源 Hadoop 搭建的數倉相比,一個很大的不同點是 MaxCompute 并不直接開放類似 HDFS 這樣的分布式檔案系統的接口,資料進出 MaxCompute 都要經由結構化資料通道 Tunnel。是以已經使用 Hadoop 建倉的使用者在選擇 MaxCompute 時,首先需要考慮的問題是資料怎麼搬遷。
搬站形式和使用場景
目前其實有多種途徑将資料遷移至 MaxCompute,下表分别列出各種途徑的優缺點及适用場景:
搬遷形式 | 需要使用的工具/服務 | 原理 | 适用場景 |
---|---|---|---|
資料內建 | DataWorks | 資料內建提供資源執行作業,拉取資料 | - 資料內建支援的資料源 - 表數量有限(目前需要按表單獨配置) |
MMA: 閃電立方 | MMA、閃電立方、OSS | 1. 郵寄閃電立方裝置進入使用者機房進行本地拷貝 1. 閃電立方郵寄回阿裡雲并挂載到 OSS 1. MaxCompute 通過 OSS 外表機制導入資料 | MaxC 外表支援的檔案格式 - 大資料量一次性搬遷 - 機房出口帶寬受限或不具備安裝專線條件 |
MMA: Hive SQL | MMA | 使用客戶 Hadoop 叢集資源執行 Hive SQL,通過 UDTF 的形式讀取資料并寫入 MaxCompute | - 最好的資料格式支援(包括 Hive 外表) - 資料量有限或具備到阿裡雲的專線 - 現有叢集能夠承擔搬站任務的資源負載 |
表格中的 MMA 為
MaxCompute Migrate Assist的縮寫,是一套輔助 Hadoop 使用者搬遷資料的工具。這套工具可以自動化批量爬取 Hive Meta,建立對應的 MaxCompute 表和分區,為客戶 Hadoop 叢集生成配套的 Hive SQL 搬遷任務或為 OSS 外表生成 MaxCompute 外表導入任務,并能夠自動排程、監督、管理這些任務的執行,以及資料搬遷完畢後的校驗工作,進而大大簡化搬站中的手工操作步驟。
本文主要讨論使用 MMA: Hive SQL 形式進行大規模資料搬站時的常見問題及解法。
MMA: Hive SQL 常見問題及解法
MMA 搬站工具的原理是在使用者側的 Hadoop 叢集執行 Hive SQL讀取資料,并使用 UDTF 通過 Tunnel 将資料寫入 MaxCompute。是以,MMA 搬站任務重度依賴于 Hive SQL 在客戶叢集的正常運作,背後其實展現對 Hadoop 叢集的管理運維水準。當叢集負載較高或情況複雜時,搬站作業可能會因多種原因失敗而延遲搬遷進度。
作業規模問題:OOM
首先常見的問題是 OOM。MMA 使用 MR 模式執行 Hive SQL,因為當輸入表檔案非常多,hive cli 在進行 SQL 解析并生成 MR 任務時非常容易記憶體不足。
現象是 hive cli 會消耗較長時間頻繁 Full GC,并最終因記憶體不足退出:
FAILED: Execution Error, return code -101 from org.apache.hadoop.hive.ql.exec.mr.MapRedTask. GC overhead limit exceeded
FAILED: Execution Error, return code -101 from org.apache.hadoop.hive.ql.exec.mr.MapRedTask. Java heap space
Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "main-EventThread"
因為記憶體不足發生在用戶端,是以需要調大 hive cli 的 Xmx 設定,如
HADOOP_CLIENT_OPTS。但具體設定生效的做法可能會因 Hadoop 部署版本不同,而且因為
某些 Hadoop 版本 bug的原因,在 java 程序啟動參數中可能有多個 Xmx,比較難以準确找到并控制實際生效的參數,是以,MMA 提供了一個更加直接的解決辦法:找到 hadoop 的啟動腳本(不同版本的 Hadoop 部署也會稍微不同,這裡以 Aliyun E-MapReduce 為例),在 exec java 的 class 前加上 MMA_OPTS 環境變量(如下),MMA 會在調用 hive cli 時通過 MMA_OPTS 将搬站作業的 Xmx 控制在 5GB,同時不影響叢集現有的預設配置。
[root@emr-header-1 bin]# which hadoop
/usr/lib/hadoop-current/bin/hadoop
[root@emr-header-1 bin]# tail /usr/lib/hadoop-current/bin/hadoop
HADOOP_OPTS="$HADOOP_OPTS $HADOOP_CLIENT_OPTS"
#make sure security appender is turned off
HADOOP_OPTS="$HADOOP_OPTS -Dhadoop.security.logger=${HADOOP_SECURITY_LOGGER:-INFO,NullAppender}"
export CLASSPATH=$CLASSPATH
exec "$JAVA" $JAVA_HEAP_MAX $HADOOP_OPTS $MMA_OPTS $CLASS "$@"
;;
esac
資料問題:HDFS
搬站作業失敗或者不穩定的另一大類原因則跟 HDFS 相關。
- 檔案未正常關閉導緻無法讀取
Caused by: java.io.IOException: Cannot obtain block length for LocatedBlock{BP-2042735465-10.1.5.152-1530865291994:blk_1789042978_715673405; getBlockSize()=1724740; corrupt=false; offset=0; locs=[DatanodeInfoWithStorage[10.40.11.121:50010,DS-ad53ff64-1a7c-4656-b89e-180b8f53bd20,DISK], DatanodeInfoWithStorage[10.40.11.79:50010,DS-dd8bc397-2889-4e04-842b-e1b5eee3bdec,DISK], DatanodeInfoWithStorage[10.40.11.83:50010,DS-2fc4ff46-47aa-41bb-932f-080456fccbd7,DISK]]}
通常是軟體 bug 導緻(Flume 常見),解決辦法
參考文檔,需要使用 hdfs 工具對指定檔案做 recoverLease 操作
hdfs debug recoverLease -path <path-of-the-file> -retries 3
- 檔案損壞導緻無法讀取
Caused by: java.io.IOException: Could not obtain the last block locations.
輸入表檔案缺失了 block,需要對表對應的 hdfs location 進行 fsck。
- HDFS IO 負載過高導緻寫出檔案機率失敗
Caused by: org.apache.hadoop.hive.ql.metadata.HiveException: java.io.IOException: Unable to close file because the last block BP-2042735465-10.1.5.152-1530865291994:blk_2290288983_1218244259 does not have enough number of replicas.
MMA 搬站作業在執行完畢之後,會向 HDFS 寫入少量作業相關資訊(Hive SQL 預設行為,非 MMA 刻意為之),如果 HDFS IO 負載特别高,有機率因寫入失敗導緻作業失敗。
此時可以選擇重跑作業,當然還有一定機率失敗,是以根治的辦法是減輕 HDFS 的 IO 壓力。IO 壓力可能來自随 Hadoop 叢集混部的其他系統,如 Presto。配置減少 Presto 執行個體數量可以緩解問題,提升搬站任務的成功率。
資源問題:vcore 優化
MMA 搬站作業是執行在客戶 Hadoop 叢集的 Hive SQL,是以,搬遷的效率實際上由作業能夠并發的 Container 數量,叢集出口帶寬,以及 MaxCompute Tunnel 服務的入口帶寬限制三者構成。
MMA 搬站作業為簡單的讀資料寫 Tunnel 操作,單個 Container 使用的 CPU 和記憶體都非常受控,通常使用 Yarn 預設配置可以滿足需求。如果因為叢集預設配置被人為改動過,額外供給了 CPU 及記憶體,隻會造成浪費。我們建議保持每個 Container 預設 1 vcore,不超過 4GB。可以通過調整叢集以下參數來降低對叢集 cpu 的浪費(MMA 搬站作業是 Map only 的 SQL,但校驗作業帶有 reducer)
mapreduce.map.cpu.vcore | 1 | |
---|---|---|
mapreduce.map.memory.mb | 4096 | MMA 對作業記憶體沒有高要求,此處可按照叢集整體 CPU 和 Memory 配比來配置 |
mapreduce.reduce.cpu.vcore |
資源問題:memory 優化
當 Hadoop 叢集處于資源超賣狀态且實際記憶體使用負載較高時,MMA 任務容易因為記憶體不足而失敗(此時記憶體不足的問題發生在 Hadoop 叢集而非送出作業的用戶端)。
在 Hadoop 與 Presto 混合部署的場景中,Presto 很可能不僅有很高的 IO 負載,在繁忙時段還會消耗大量的記憶體,進而影響 Hive SQL 作業的正常運作。典型的報錯如下:
# There is insufficient memory for the Java Runtime Environment to continue.
# Native memory allocation (mmap) failed to map 232259584 bytes for committing reserved memory.
Java HotSpot(TM) 64-Bit Server VM warning: INFO: os::commit_memory(0x00000007aa780000, 232259584, 0) failed; error='Cannot allocate memory' (errno=12)
此時減小 MMA 作業并發可以在一定程度上降低作業失敗的機率,根本性的做法需要控制 Presto 記憶體使用。