此文來自於《Hive性能調優與實戰》,寫的真不錯,如有需要自行購買
京東 在這裏僅用以筆記備忘,侵刪!
一、什麼是mapreduce的shuffle ?
shuffle的過程應該是從mapper的map方式輸出到Reduce方法輸入的過程. 非常關鍵的一個環節,制約了性能,保證了可以在廉價機器上可靠運行的一個環節。
在Mapper的map方法中,context.write 會講數據計算所在的分區後寫入到內存緩衝區(100mb)達到閾值0.8 也就是當寫到80mb的時候開始啓動新線程寫入hdfs臨時目錄。目的是避免單行數據頻繁寫,以減輕磁盤負載。
在寫到hdfs的過程中,爲了下游的reducer任務順序拉取數據,會講數據排序後在寫入到臨時文件,當整個map執行介紹後會講臨時文件歸併成一個文件。試想如果不對文件進行排序歸併,那麼下游的reducer任務拉取數據的時候就會頻繁搜索磁盤,使得順序讀變爲了隨機讀,極大的影響IO負載。
早期的spark shuffle 默認採用Hash based shuffle 會產生大量的臨時文件,以至於下游讀取需要很多的文件句柄,性能低下且容易oom。 因此spark 1.1開始引入Sort based shuffle才得意改善,且在spark2.0 正式廢棄 Hash Based Shuffle. 事實上 Sort based shuffle也是借鑑了hasoop shuffle的思想。
繼續說reduce,reduce任務啓動後回啓動拉取數據的線程,從HDFS拉取所需要的數據。
試想爲啥不直接map完了直接推到對應的reduce節點上呢,這樣可以節省寫入磁盤的操作,性能更高?
因爲採用緩存到hdfs,當一個reducer任務因爲某些原因導致異常結束的時候,再啓用一個新的依然可以讀取到正確的結果。
從hdfs拉取數據回先緩存到內存緩衝區,當數據達到一定的閾值纔會講內存中的數據寫入到內存或者磁盤文件中。文件數據量達到一定的量級還需要進行歸併。(常見的表連接階段)
二、發現並優化hive中的性能問題
收集表的元數據:
1、收集表的元數據
analyze table 表名 compute statistics
2、收集字段的元數據
analyze table 表名 compute statistics for columns
3、收集所有分區的元數據 (可能超時)
analyze table 表名 partition(分區列) compute statistics;
4、收集指定分區元數據
analyze table 表名 partition(分區列=分區值) compute;
5、收集所有分區列的元數據
analyze table 表名 partition(分區列) compute statistics for columns;
使用元數據做監控:
(1) 監控普通表存儲的文件的平均大小 (2倍文件塊大小)
SELECT
TBL_NAME,avgfilesize'fileSize(Mb)'
FROM (
SELECT
tp.totalSize/(1024*1024)/numFiles avgfilessize,TBL_NAME
FROM DBS d
INNER join TBLS t on d.DB_ID = t.DB_ID
left join (
SELECT TBL_ID,
MAX(case PARAM_KEY when 'numFiles' then PARAM_VALUE ELSE 0 END) numFiles,
MAX(case (PARAM_KEY when 'totalSize' then PARAM_VALUE ELSE 0 END ) totalSize
from TABLE_PARAMS
GROUP by TBL_ID
) tp on t.TBL_ID = tp.TBL_ID
where d.`NAME` = 'database name'
and tp.numFiles is not NULL
and tp.numFiles > 0
) a where avgfileszie > hdfs文件塊大小*2;
(2)監控分區存儲的文件的大小
SELECT
TBL_NAME,part_name,avgfilesize'fileSize(Mb)'
FROM (
SELECT
pp.totalSize/(1024*1024)/numFiles avgfilesize,TBL_NAME,part.PART_NAME
FROM DBS d
INNER join TBLS t on d.DB_ID = t.DB_ID
INNER join PARTITIONS part on t.TBL_ID = part.TBL_ID
left join (
SELECT PART_ID,
-- 每個表存儲的文件個數
MAX(case PARAM_KEY when 'numFiles' then PARAM_VALUE ELSE 0 END) numFiles,
-- 文件存儲的大小
MAX(case (PARAM_KEY when 'totalSize' then PARAM_VALUE ELSE 0 END ) totalSize
from PARTITION_PARAMS
GROUP by PART_ID
) pp on part.PART_ID = pp.PART_ID
where d.`NAME` = 'database name'
and pp.numFiles is not NULL
and pp.numFiles > 0
) a where avgfileszie > hdfs文件塊大小*2;
(3)監控大表不分區的的表
select t.TBL_NAME
FROM DBS d
inner join TBLS t on d.`DB_ID` = t.`DB_ID`
inner join (
select `TBL_ID`,max(case `PARAM_KEY` when 'totalSize' then `PARAM_VALUE` else 0 end) totalSize
from `TABLE_PARAMS`
group by `TBL_ID`
) tp on t.`TBL_ID` = tp.`TBL_ID`
left join
(
select distinct `TBL_ID` from PARTITIONING
) part on t.`TBL_ID` = part.`TBL_ID`
where d.`NAME` = '監控的庫名'
and part.`TBL_ID` is null
and totalSize/1024/1024/1024 > 30
(4)監控hive表的分區數
-- 監控hive的分區數
SELECT
t.TBL_NAME '表名',d.`NAME` '庫名', COUNT(part.PART_NAME) '分區數'
FROM
DBS d
INNER JOIN TBLS t on d.DB_ID = t.DB_ID
INNER join `PARTITIONS` part on part.TBL_ID = t.TBL_ID
WHERE d.`NAME` = '需要監控的庫名'
GROUP by t.TBL_NAME,d.`NAME`;
三、監控當前集羣狀態
1、獲取集羣的狀態信息
get http://xx:8088/ws/v1/cluster
2、獲取集羣任務的整體信息
get http://xx:8088/ws/v1/cluster/metrics
3、獲取集羣任務的運行信息
get http://xx:8088/ws/v1/cluster/apps
4、單個任務的運行信息
get http://xx:8088/ws/v1/cluster/apps/任務ID
5、獲取資源調度分配的信息
get http://xx:8088/ws/v1/cluster/scheduler
四、聊聊parquet 和orc存儲格式
列式存儲格式普遍具有如下特點:
- 高效的壓縮編碼,用於降低存儲成本
- 高效的讀取能力,用於支撐快速查詢
parquet具有如下特點;
- 列式存儲
- 自帶Schema
- 具備Predicate Filter特性
實踐證明:使用orc存儲可以有效藉助於元數據快速篩掉不需要的數據,在查詢時候鎖消耗 的集羣資源比parquet少。
具體參考:https://zhuanlan.zhihu.com/p/35622907
五、數據傾斜解決方案
-
不可拆分大文件引發的傾斜
解決:寫入的時候隨機打散分多份,或者使用bzip2,zip等支持讀取時分割的壓縮算法。 -
業務無關的數據引發的數據傾斜
解決:沒啥好說的,過濾吧 -
多維聚合計算引發的數據傾斜
比如:rollup 可以嘗試將其拆分成普通的分組聚合。
-
無法削減中間結果的數據量引發的數據傾斜
解決:一般情況下開啓 hive.groupby.skewindata,但是對於collect_list的聚合函數沒有效果,因爲該函數要求全量操作數據的中間結果,明顯起不到作用,反而會因爲引入新的作業增加了磁盤和網絡IO開銷,從而導致性能更爲低下。解決辦法,調整reduce執行內存大小,使用mapreduce.reduce.memory.mb。 但是如果hive客戶端連接的hiveserver2服務一次性需要返回處理的數據量很大,超過了hiveserver2設置的最大JAVA堆也是會導致內存溢出的,所以請評估好在用。 -
兩個hive表join時候引起的數據傾斜
hive的做法是,啓動兩個作業,第一個處理麼有傾斜的數據,第二個處理傾斜的數據將其存到分佈式緩存中,分發到各個map任務所在節點,在map階段完成join 即mapjoin ,避免shuffle ,從而避免數據傾斜。