數據遷移心得

  前幾天出差,去客戶現場幫忙遷移數據,通過幾天的奮戰,終於將遷移數據自動化起來,而且能夠日跑批操做,這裏小編就跟你們分享下,這其中踩過的坑(也多是實戰經驗不豐富致使)。
  首先,榮小編我抱怨一下,不是本身熟悉的開發環境真的有些難過,給一臺電腦,咱不說沒有IDE,就連java都沒有安裝,鏈接數據庫的工具也沒有,惟一值得慶幸的是有xshell,可是徹底不符合我的快捷鍵的喜愛,沒辦法,想要開發高效,本身動手配置吧。單單是配置這些開發環境就整整犧牲了小編一上午的時間,還好後期開發有明顯的提速。中午吃個飯,下午進入正題。
  下午拿到遷移任務,發現一個庫中有不少表,其中表有大有小,當時我沉默了幾秒鐘,感受這個星期是交代在這裏了。這裏小編在那幾秒鐘的沉默中也把這個遷移流程想了一下,首先數據是存在關係型數據庫中的,而後咱們要經過sqoop將數據上傳到HDFS中,而後用hive的外表去映射這些數據,最終創建有索引的內表來存儲一份完整的數據。內表通常都是分區,分桶,且有索引的orc表,查詢速度明顯比外表快不少。那麼接下來小編就將這其中的步驟,一點點的分析下。java

前期準備:

   拿到一個庫的數據時,咱們首先分析下這裏有哪些表比較大,哪些表比較小,將大表和小表分開,使用不一樣的遷移方法,通常都是客戶提供每張表的數據條數,若是沒有的話,只能selecct count(*) from table; 將這些表的數據查出來,不只便於區分大小表,並且對後期數據覈對有較大的幫助。shell

1. 從關係型數據庫將數據遷移到HDFS中

  這裏遷移數據小編是用的sqoop,雖然sqoop比較慢,可是學習成本相對較低,並且便於批量的生成語句,對開發要求沒那麼高。首先先測試一個sqoop是否能夠成功的遷移數據,而後編寫腳本批量的生成sqoop語句,最後調用這些語句,後臺並行的遷移數據。這裏小編先說說使用sqoop的幾個小竅門:數據庫

  • 若是集羣的資源比較充分,通常新集羣是沒有什麼生產任務的,咱們的sqoop語句中能夠加入:
    -m 這個參數能夠設置爲>1 ,表示並行多個map去抽取數據。
    --split-by 固然-m 參數設置大於後,要同時設置這個參數,表示以表中的哪個字段去分map並行。

    這裏選取--split-by 儘可能使用表中比較分散的字段,保證每個map任務抽取的數據量都大體相同。app

  • 若是表的數據量比較大,好比超過億條,咱們這裏就須要將這個表分紅多個sqoop去抽取:ide

    --query : 指定where後的條件,抽取部分數據
       這樣的好處是:若是隻有一個sqoop任務,抽取了90%的數據後,發現sqoop任務掛了,那麼本次抽取失敗,不只耗時,並且數據沒有抽取到。分多個sqoop任務,不只可並行,並且每一個任務的數據量也不大,若是有任務掛了,只須要抽象抽取那個where條件下的數據即,而且對於找錯也有極大的幫助。
       分區字段的選取也一樣重要,這裏通常都是使用日期做爲where的後的條件,保證每一個sqoop任務分的的數據量相差無幾。工具

    • sqoop抽取數據的目錄規劃
      #小表目錄規劃
      /tmp/庫名/表名
      #大表的目錄規劃
      /tmp/庫名/表名/分區名
  • query語句:在sqoop命令中,咱們編寫查詢語句去抽取數據時,切記不要:oop

    -- ×
    select * from table;
    -- √
    select 字段1,字段2.... from table;
    否則可能會致使sqoop抽取速度變慢,甚至可能致使沒有抽取到數據。
       當咱們注意了以上的內容後,就能夠編寫腳本批量的生成每張表的sqoop語句了,根據庫名.表名,獲取關係型數據庫中表的元數據,最後將sqoop組裝起來。最後在編寫任務腳本,定時執行這些sqoop語句。
    實際數據分享:
       這裏小編測試過,數據量比較大時,多sqoop和單sqoop的耗時:
    以600G數據爲例:
       - 多sqoop 並行抽取數據耗時:3~4小時。
       - 單sqoop 抽取數據耗時:12小時以上。
       - 單sqoop && (-m 1)抽取5千萬條數據,大概是27分鐘。學習

2. 創建外表映射

   說白了就是將抽取到的數據,在hive中經過外表的方式映射出來,其實這裏沒什麼難的,主要是看客戶若是要求,多是外表單獨一個庫,或者外表的名稱統一是:表名_ext。可是切記,不要手動的去編寫建表語句,若是表有百張以上,心態容易炸,這裏可使用關係型數據庫的元數據 ,生成hive的建表語句的,這裏咱們與MySQL爲例:測試

SELECT CONCAT('create table ', TABLE_NAME, '(', substring(column_info, 1, length(column_info) - 1), ')', ' comment ', '"', TABLE_COMMENT, '"', ';')
FROM (SELECT TABLE_NAME, TABLE_COMMENT, group_concat(CONCAT(COLUMN_NAME, ' ', DATA_TYPE, ' comment ', '"', COLUMN_COMMENT, '"')) AS column_info
FROM (SELECT t1.TABLE_NAME, CASE WHEN t2.TABLE_COMMENT = NULL THEN t1.TABLE_NAME ELSE t2.TABLE_COMMENT END AS TABLE_COMMENT, COLUMN_NAME, CASE WHEN DATA_TYPE = 'varchar' THEN 'string' WHEN DATA_TYPE = 'int' THEN 'int' WHEN DATA_TYPE = 'tinyint' THEN 'tinyint' WHEN DATA_TYPE = 'decimal' THEN 'double' WHEN DATA_TYPE = 'datetime' THEN 'string' WHEN DATA_TYPE = 'timestamp' THEN 'string' WHEN DATA_TYPE = 'float' THEN 'double' WHEN DATA_TYPE = 'double' THEN 'double' WHEN DATA_TYPE = 'bigint' THEN 'bigint' END AS DATA_TYPE, CASE WHEN COLUMN_COMMENT = NULL THEN COLUMN_NAME ELSE COLUMN_COMMENT END AS COLUMN_COMMENT
FROM COLUMNS t1 JOIN TABLES t2 ON t1.TABLE_NAME = t2.TABLE_NAME
WHERE t1.TABLE_NAME = 't_app_equipment_status'
) t3
GROUP BY TABLE_NAME, TABLE_COMMENT
) t4;

網上這樣的例子不少,這裏小編就不在介紹。當外表創建好以後,最好覈對一下數據量的大小,對比下關係型數據庫中表的數據和hive中的數據是否相同,這樣驗證了sqoop這一環節是否有數據丟失的狀況。
遇到的坑:
  當大表咱們在分區抽取時,是沒法直接映射成爲外表的,咱們須要創建範圍分區表,將表的分區目錄映射到各個分區上。優化

3. 創建高效的內表

   其實這一步就是將,外表的數據,insert到一張和外表字段相同的通過優化的內表中,這張內表通常都是分區分桶,創建索引,或者基於閃存的表,反正就是查詢的速度大大提升的一張表,也叫作業務表。
   小編這裏用的是一種基於閃存的高效查詢的,企業內部開發的一種表結構。小編這裏介紹一下如何肯定分桶字段:分桶的好處是
   (1)得到更高的查詢處理效率。桶爲表加上了額外的結構,Hive 在處理有些查詢時能利用這個結構。具體而言,鏈接兩個在(包含鏈接列的)相同列上劃分了桶的表,可使用 Map 端鏈接 (Map-side join)高效的實現。好比JOIN操做。對於JOIN操做兩個表有一個相同的列,若是對這兩個表都進行了桶操做。那麼將保存相同列值的桶進行JOIN操做就能夠,能夠大大較少JOIN的數據量。
   (2)使取樣(sampling)更高效。在處理大規模數據集時,在開發和修改查詢的階段,若是能在數據集的一小部分數據上試運行查詢,會帶來不少方便。
   那麼若是肯定分桶字段呢,通常的若是有主鍵的表就使用主鍵做爲分桶字段,若是沒有主鍵的表,找幾個比較分散的字段使用:

select count(distinct feild) from table;

找出數據最大的那個字段做爲分桶字段。具體的分桶數,這裏建議是一個質數,由於若是是一個非質數,那麼可能致使分桶不均勻,由於若是分桶數是9的話,那麼字段值若是爲1八、27都會分到一個桶中,可能會致使桶「熱點」。

4. 外表insert 到 內表中

   這個過程是耗時僅次於sqoop的過程,因爲咱們的內表創建的分區,那麼在這個步驟中咱們須要使用hive的動態分區插入,插入語句通常都是:

insert into table_1 partition(par_field) select field1.field2...from table_2 ;

這裏須要注意的是select 最後一個字段必定要是分區字段。
   當咱們insert 後,須要覈對下是否全部的數據所有insert成功,此時:外表數據量=內表數據量=關係型數據庫數據量

5. 日增量數據的處理

   當咱們完成數據遷移後,其實外表至關於一箇中轉站,僅僅是將數據中轉到內表中,若是咱們確保了內表中有一份完整的數據,此時能夠將外表的數據清空,這也是爲何咱們將外表的location 設置爲/tmp下 的緣由,清空外表數據後,將日增數據抽取到外表的location地址上,而後全量的將外表數據insert到內表中,就保證了日增量數據的成功導入到hive。

相關文章
相關標籤/搜索