sqoop-import 並行抽數及數據傾斜解決

最近在數據中臺的數據抽數優化工作,由於單表數據量太大(每天千萬級別)導致sqoop抽數使用單實例報內存溢出以及抽數時間過長,決定採用sqoop的多實例並行抽數,參考了一些文檔,但同時遇到了一些問題,趁有點時間把遇到問題的解決方法寫下來供大家借鑑。 

並行化

sqoop-常用命令及參數:https://www.yuque.com/shanyu-aqvcy/hkqgb7/vngsox

sqoop 抽數的並行化主要涉及到兩個參數:num-mappers:啓動N個map來並行導入數據,默認4個;split-by:按照某一列來切分表的工作單元。

具體原理: 

Sqoop在import時,需要制定split-by參數。Sqoop根據不同的split-by參數值來進行切分,然後將切分出來的區域分配到不同map中。每個map中再處理數據庫中獲取的一行一行的值,寫入到HDFS中。同時split-by根據不同的參數類型有不同的切分方法,如比較簡單的int型,Sqoop會取最大和最小split-by字段值,然後根據傳入的num-mappers來確定劃分幾個區域。 比如select max(split_by),min(split-by) from得到的max(split-by)和min(split-by)分別爲1000和1,而num-mappers爲2的話,則會分成兩個區域(1,500)和(501-100),同時也會分成2個sql給2個map去進行導入操作,分別爲select XXX from table where split-by>=1 and split-by<500和select XXX from table where split-by>=501 and split-by<=1000。最後每個map各自獲取各自SQL中的數據進行導入工作。

            image.png

看到這裏大家應該會明白:我們通過num-mappers  參數控制並行度,split-by參數控制數據分割字段,就可以做到抽數並行化。

數據傾斜

問題分析及闡述

但是並行化後,問題隨之而來那就是sqoop的數據分割策略不夠優秀導致的數據傾斜。打斷下,在具體闡述數據傾斜以及解決方法之前,先提一個知識點後面會用到。

sqoop import 抽數查詢願數據的時候主要有兩者方式:--table  方式:全量數據抽取  --query 方式:增加檢索條件部分數據抽數,當然也可以where 1=1 進行全量操作,有很多人應該注意到 --query 語句後面必須要加一個 "and $CONDITIONS" 字符串,不加還報錯。那$CONDITIONS 到底是幹什麼用的呢?其實它的作用是數據分割條件的佔位符,也就是說最終數據查詢語句中的$CONDITIONS 會被split-by>=501 and split-by<=1000  這樣的分割條件替換。

數據傾斜是啥呢?在說數據傾斜之前,我們設想數據並行抽數最理想的情況就是所有的並行實例同時完成,木桶原理,數據抽數時間的長短取決於耗時最長的那個實例。由於各個實例被分配的數據量不均而導致分配到數據量較少的實例早早完成,而被分配大量數據的實例遲遲無法完成,導致整個作業運行時間很長的現象就是數據傾斜導致的。數據傾斜概括爲一句話:數據分配不均。

從上面的具體原理瞭解到數據的分割方法是根據數據表的某個字段去分割的,但是從大量的實踐經驗來sqoop split-by 的數據切分策略對字符串類型字段支持及其不好,不但有嚴重的數據傾斜現象,同時還存在數據重複抽取、數據漏抽的現象,數據質量都沒有辦法保障肯定是允許的。那麼切分策略對int(整數)類型的支持呢?如果數據分佈不均同樣會造成數據傾斜的問題?

闡述下切分策略對int類型的切分機制。在指定好int的split-by 字段後(這裏用id代替,注意這裏的id就是一個普通的int 字段,不是大家想的數據主鍵id)如果不設定--boundary-query 參數,默認使用(select MIN(id) , MAX(id) FROM table)確定數據的上下界,確定總體數量 除以num-mappers 確定每個實例數據量

例如:MIN(id) =100   MAX(id)=500  num-mappers 爲 4

select * from table where id >= 100  and id < 200;

select * from table where id >= 200  and id < 300;

select * from table where id >= 300  and id < 400;

select * from table where id >= 400  and id <= 500;

    可以看出問題來了,如果id數據分佈不均及id重複同樣會出現數據傾斜,例如:100到200有10條數據,400到500有10000條數據。

從此得出結論想要避免數據傾斜,對split-by指定字段的要求是 int類型同時數據分佈均勻,滿足這樣的要求的表只有極少數的有自增主鍵的表才能滿足,我相信大多數的表不會滿足這樣的要求,臨時增加字段肯定是不現實的。

數據傾斜解決方法

在瞭解數據切分策略之後,在數據表沒有符合要求的字段的情況下,我們需要自己臨時簡單創建理想的字段。

這裏需要使用--query 方式:涉及參數  --query、--split-by、--boundary-query

--query: select column1、 column2、 column3、 columnN from (select ROWNUM() OVER() AS ETL_ID, T.* from table T where xxx )  where $CONDITIONS

--split-by: ETL_ID

--boundary-query: select 1 as MIN , sum(1) as MAX from table where xxx

具體原理就是通過ROWNUM() 生成一個嚴格均勻分佈的字段,然後指定爲分割字段。

ok,就是這麼簡單,是不是恍然大悟

實測一張1500w左右數據量 30多字段 表開30 mappers 耗時大概3分鐘。

如有問題歡迎留言,共同探討。

發佈了7 篇原創文章 · 獲贊 2 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章