1. 程式人生 > 其它 >hive小檔案過多問題解決

hive小檔案過多問題解決

技術標籤:問題總結hadoopSQLhive大資料hadoop

起因

資料中臺當前有一張流水類表,存在3200個分割槽,230w個數據檔案,150億條資料,導致該表查詢起來及其麻煩,更令人糟心的是,業務人員不懂查詢方式,經常有人使用select *的方式查詢該表,導致hiveserver2經常炸掉,極大影響叢集的使用,因此,我們決定處理掉這個問題。

我們來看下是什麼原因導致這個問題

首先,檔案數量和大小會影響Mapper任務的數量,所以小檔案越多,mapper任務越多,每個mapper任務會啟動一個JVM,所以這些任務初始化和執行會消耗大量資源。而且在NameNode中每個檔案大約佔150位元組,小檔案問題會直接帶來NameNode的壓力巨大,從而導致HDFS的穩定性,同時對HDFS日常的資料讀寫帶來效能下降。

解決方法
  1. 從源頭解決,在日增資料的指令碼中加入引數設定,約束生成的小檔案數量,引數示例如下

     set mapred.max.split.size=25000000;
     set mapred.min.split.size.per.node=10000000;
     set hive.hadoop.supports.splittable.combineinputformat=true;
     set mapred.min.split.size.per.rack=10000000;
     set hive.exec.compress.output=true;
     set hive.merge.mapfiles=true;
     set hive.merge.mapredfiles=true;
     set hive.merge.size.per.task=256000000;
     set hive.merge.smallfiles.avgsize=16000000;
     set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
    

附贈一份從其他地方copy過來的引數說明

引數說明
-----設定Map輸入合併小檔案的相關引數
set mapred.max.split.size=256000000每個Map最大輸入大小(這個值決定了合併後文件的數量)
set mapred.min.split.size.per.node=100000000一個節點上split的至少的大小(這個值決定了多個DataNode上的檔案是否需要合併)
set mapred.min.split.size.per.rack=100000000一個交換機下split至少的大小(這個值決定了多個交換機上的檔案是否需要合併)
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
執行Map前進行小檔案合併
-----設定Map輸出和Reduce輸出進行合併的相關引數
set hive.merge.mapfiles = true設定map端輸出進行合併,預設為true
set hive.merge.mapredfiles = true設定reduce端輸出進行合併,預設為false
set hive.merge.size.per.task = 25610001000設定合併檔案的大小
set hive.merge.smallfiles.avgsize=16000000當輸出檔案的平均大小小於該值時,啟動一個獨立的MapReduce任務進行檔案的Merge
-----設定
set parquet.compression=GZIPparquet格式的壓縮格式
set hive.exec.reducers.bytes.per.reducer=115000000設定執行時Reduce的數量
set hive.exec.reducers.max=120000000;設定執行時Reduce的最大數量
  1. 合併hdfs中已有的小檔案,這也是本文的重點

    合併小檔案有兩種思路。一是使用hive的原生工具concatenate來合併小檔案,sql示例如下

alter table app.example_orc partition (dt=“20200202”) concatenate;

但是,concatenate只支援RCFile和ORC格式的表,在其他如parquet格式中不適用,因此,如果是新的數倉,可以直接規定所有表使用orc格式來支援這個工具,這樣小檔案過多可以使用hive自帶命令 concatenate 快速合併。

Tips:
1、concatenate 命令只支援 RCFILE 和 ORC 檔案型別。
2、使用concatenate命令合併小檔案時不能指定合併後的檔案數量,但可以多次執行該命令。
3、當多次使用concatenate後文件數量不在變化,這個跟引數 mapreduce.input.fileinputformat.split.minsize=256mb 的設定有關,可設定每個檔案的最小size。
4、只能針對分割槽使用concatenate命令。

另一種方法就顯得比較繁瑣和笨重,那就是通過新建臨時表,將現有分割槽中的表匯入臨時表再回寫的方法來解決該問題,因為我們系統中該表只需要處理部分分割槽,因此考慮這樣處理,如果你是全部分割槽均存在這種問題,可以考慮直接通過把備用表改名的形式,避免多一次I/O。
示例程式碼如下

  1. 建立臨時表
create table bs_collect.tsconfirm_transtion like bs_collect.tsconfirm;

--查詢小檔案數量命令
--hdfs dfs -count {path}
  1. 資料寫入臨時表
set mapred.max.split.size=25000000;
set mapred.min.split.size.per.node=10000000;
set hive.hadoop.supports.splittable.combineinputformat=true;
set mapred.min.split.size.per.rack=10000000;
set hive.exec.compress.output=true;
set hive.merge.mapfiles=true;
set hive.merge.mapredfiles=true;
set hive.merge.size.per.task=256000000;
set hive.merge.smallfiles.avgsize=16000000;
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
set hive.exec.dynamic.partition.mode=nonstrict;
insert overwrite table bs_collect.tsconfirm_transtion partition(c_tano,d_cdate)
select * from bs_collect.tsconfirm where d_cdate<'2017-09-01';
  1. 資料檔案回寫
set mapred.max.split.size=25000000;
set mapred.min.split.size.per.node=10000000;
set hive.hadoop.supports.splittable.combineinputformat=true;
set mapred.min.split.size.per.rack=10000000;
set hive.exec.compress.output=true;
set hive.merge.mapfiles=true;
set hive.merge.mapredfiles=true;
set hive.merge.size.per.task=256000000;
set hive.merge.smallfiles.avgsize=16000000;
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
set hive.exec.dynamic.partition.mode=nonstrict;
insert overwrite table bs_collect.tsconfirm partition(c_tano,d_cdate)
select * from bs_collect.tsconfirm_transtion where d_cdate<'2017-09-01';
結果

這是源表的資料檔案數量
在這裡插入圖片描述
這是處理後的
在這裡插入圖片描述
可以看到,檔案數量明顯減少。