天天看點

MaxCompute 搬站的原理、實踐以及常見問題

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 記憶體使用。