1. 程式人生 > 資料庫 >Spark SQL 小檔案問題處理

Spark SQL 小檔案問題處理

在生產中,無論是通過SQL語句或者/Java等程式碼的方式使用處理資料,在Spark SQL寫資料時,往往會遇到生成的小檔案過多的問題,而管理這些大量的小檔案,是一件非常頭疼的事情。

大量的小檔案會影響Hadoop叢集管理或者Spark在處理資料時的穩定性:

1. Spark SQL寫Hive或者直接寫入HDFS,過多的小檔案會對NameNode記憶體管理等產生巨大的壓力,會影響整個叢集的穩定執行

2. 容易導致task數過多,如果超過引數spark.driver.maxResultSize的配置(預設1g),會丟擲類似如下的異常,影響任務的處理

Caused by: org.apache.spark.SparkException: Job aborted due to stage failure: Total size of serialized results of 478 tasks (2026.0 MB) is bigger than spark.driver.maxResultSize (1024.0 MB)

 

當然可以通過調大spark.driver.maxResultSize的預設配置來解決問題,但如果不能從源頭上解決小檔案問題,以後還可能遇到類似的問題。

此外,Spark在處理任務時,一個分割槽分配一個task進行處理,多個分割槽並行處理,雖然並行處理能夠提高處理效率,但不是意味著task數越多越好。如果資料量不大,過多的task執行反而會影響效率。

下面通過一個例子,Spark SQL寫資料時,導致產生分割槽數"劇增"的典型場景,通過分割槽數"劇增",以及Spark中task數和分割槽數的關係等,來倒推小檔案過多的可能原因(這裡的分割槽數是指生成的DataSet/RDD的分割槽數,不是Hive分割槽表的分割槽概念):

1. 現象

1) 對錶test_tab進行寫入操作
2) t1的分割槽數是100,t2的分割槽數是200,union all後生成的tmp分割槽數是300
3) test_tab產生的小檔案數基本也在300左右
select * from t1 union all select * from t2 as tmp;insert overwrite table test_tab select * from tmp;

 

2. 分析

1)執行上述insert操作時的分割槽並行度,主要受tmp的分割槽數(對應一個DataSet)影響,

2)tmp的分割槽數主要受t1、t2以及union all的影響

3)暫且不考慮t1或t2是物理表還是經過其他處理生成的臨時表,它們的分割槽數是確定的,這裡主要看經過union all處理後,生成的tmp的分割槽數和t1、t2的分割槽數有何關係?

4)Spark SQL語句中的union all對應到DataSet中即為unionAll運算元,底層呼叫union運算元

在之前的文章中已經對Spark RDD中的union運算元對union產生的新的RDD的分割槽數是如何受被union的多個RDD的影響的,做過詳細介紹,這裡直接給出結論:

同樣的這種機制也可以套用到Spark SQL中的DataSet上,那麼就很好解釋了tmp的分割槽數為什麼等於t1和t2的分割槽數的和。

最後,Spark中一個task處理一個分割槽從而也會影響最終生成的檔案數。

當然上述只是以Spark SQL中的一個場景闡述了小檔案產生過多的原因之一(分割槽數過多)。在數倉建設中,產生小檔案過多的原因有很多種,比如:

1. 流式處理中,每個批次的處理執行儲存操作也會產生很多小檔案

2. 為了解決資料更新問題,同一份資料儲存了不同的幾個狀態,也容易導致檔案數過多

那麼如何解決這種小檔案的問題呢?

1. 通過repartition或coalesce運算元控制最後的DataSet的分割槽數

注意repartition和coalesce的區別,具體可以參考文章

2. 將Hive風格的Coalesce and Repartition Hint 應用到Spark SQL需要注意這種方式對Spark的版本有要求,建議在Spark2.4.X及以上版本使用,示例:

INSERT ... SELECT /*+ COALESCE(numPartitions) */ ...
INSERT ... SELECT /*+ REPARTITION(numPartitions) */ ...

 

3. 小檔案定期合併

可以定時通過非同步的方式針對Hive分割槽表的每一個分割槽中的小檔案進行合併操作

上述只是給出3種常見的解決辦法,並且要結合實際用到的技術和場景去具體處理,比如對於HDFS小檔案過多,也可以通過生成HAR 檔案或者Sequence File來解決。

推薦文章:


關注,獲取更對技術乾貨