天天看點

徹底解決Hive小檔案問題

關注公衆号:

大資料技術派

,回複:

資料

,領取

1024G

資料。

最近發現離線任務對一個增量

Hive

表的查詢越來越慢,這引起了我的注意,我在

cmd

視窗手動執行

count

操作查詢發現,速度确實很慢,才不到五千萬的資料,居然需要

300s

,這顯然是有問題的,我推測可能是有小檔案。

我去

hdfs

目錄檢視了一下該目錄:

徹底解決Hive小檔案問題

發現确實有很多小檔案,有480個小檔案,我覺得我找到了問題所在,那麼合并一下小檔案吧:

insert into test select * from table distribute by floor (rand()*5);
           

這裡使用

distribute by

進行了一個小檔案的合并,通過

rand() * 5

,保證了從map端輸出的資料,最多到5個

reducer

,将小檔案數量控制了下來,現在隻有3個檔案了。

徹底解決Hive小檔案問題

合并小檔案後,再次做同樣的查詢,

15s

就完成了。确實忽略了,增量資料會導緻小檔案,應該在當初做的時候就做定時的小檔案合并,而不是等到現在才發現。

因為這個表每天是有增量資料進去的,增量資料會單獨生成一個檔案,因為增量資料本身不大,日積月累就形成了大量小檔案。不僅對

namenode

的記憶體造成壓力,對map端的小檔案合并也有很大壓力。

小檔案産生的原因

  • 動态分區插入資料的時候,會産生大量的小檔案;
  • 資料源本身就包含有大量的小檔案;
  • 做增量導入,比如Sqoop資料導入,一些增量insert等;
  • 分桶表,分桶表通常也會遇到小檔案,本質上還是增量導入的問題;
  • 可以修改的表,這種Hive表是可以進行修改的,通過配置

    stored as orc TBLPROPERTIES ("transactional"="true")

    ,這種表最坑,每天都會有一個快照,到後面10G大小的資料,表檔案體積可以達到600G,時間越長越大;

小檔案的問題有很多,實際中各種原因,由于自己的不小心,前期沒有做好預防都會産生大量小檔案,讓線上的離線任務神不知鬼不覺,越跑越慢。

小檔案的危害

  1. 給namenode記憶體中fsImage的合并造成壓力,如果namenode記憶體使用完了,這個叢集将不能再存儲檔案了;
  2. 雖然map階段都設定了小檔案合并,

    org.apache.hadoop.hive.ql.io.CombineHiveInputFormat

    ,太多小檔案導緻合并時間較長,查詢緩慢;

小檔案的解決方案

徹底解決小檔案,分為了兩個方向,一個是小檔案的預防,一個是大量小檔案問題已經出現了,我們該怎麼解決。

1. 小檔案的預防

網上有些解決方案,是調節參數,這些參數在我使用的

Hive2

是預設都開啟了的:

//每個Map最大輸入大小(這個值決定了合并後檔案的數量)
set mapred.max.split.size=256000000;  
//一個節點上split的至少的大小(這個值決定了多個DataNode上的檔案是否需要合并)
set mapred.min.split.size.per.node=100000000;
//一個交換機下split的至少的大小(這個值決定了多個交換機上的檔案是否需要合并)  
set mapred.min.split.size.per.rack=100000000;
//執行Map前進行小檔案合并
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat; 
//設定map端輸出進行合并,預設為true
set hive.merge.mapfiles = true
//設定reduce端輸出進行合并,預設為false
set hive.merge.mapredfiles = true
//設定合并檔案的大小
set hive.merge.size.per.task = 256*1000*1000
//當輸出檔案的平均大小小于該值時,啟動一個獨立的MapReduce任務進行檔案merge。
set hive.merge.smallfiles.avgsize=16000000
           

有些公司用的版本不同,低版本可能有些配置不一樣,最好檢查一下上面這些配置是否設定,然後根據自己的實際叢集情況進行設定。

小檔案的預防,主要還是要根據小檔案的産生原因,來進行預防。

  1. 動态分區插入的時候,保證有靜态分區,不要誤判導緻産生大量分區,大量分區加起來,自然就有大量小檔案;
  2. 如果源表是有大量小檔案的,在導入資料到目标表的時候,如果隻是

    insert into dis select * from origin

    的話,目标表通常也有很多小檔案。如果有分區,比如

    dt, hour

    ,可以使用

    distribute by dt, hour

    ,保證每個小時的資料在一個reduce裡面;
  3. 類似

    sqoop

    增量導入,還有

    hive

    一些表的查詢增量導入,這些肯定是有小檔案的,需要進行一周甚至一天定時任務的小檔案合并。

2. 小檔案的解決

上面是平時開發資料任務時候,小檔案的預防,但如果由于我們的大意,小檔案問題已經産生了,就需要解決了。通常就是

insert overwrite

了。

insert overwrite table test [partition(hour=...)] select * from test distribute by floor (rand()*5);
           

注:這個語句把

test

表的資料查詢出來,

overwrite

覆寫

test

表,不用擔心如果

overwrite

失敗,資料沒了,這裡面是有事物性保證的,可以觀察一下執行的時候,在test表

hdfs

檔案目錄下面有個臨時檔案夾。如果是分區表,加上

partition

,表示對該分區進行

overwrite

如果是orc格式存儲的表,還可以使用

alter table test [partition(...)] concatenate

進行小檔案的合并,不過這種方法僅僅适用于orc格式存儲的表。

猜你喜歡

Hadoop3資料容錯技術(糾删碼)

Hadoop 資料遷移用法詳解

Flink實時計算topN熱榜

數倉模組化分層理論

一文搞懂Hive的資料存儲與壓縮

大資料元件重點學習這幾個

繼續閱讀