sparksql運算調優紀事(三)——repartition數據傾斜處理

版本

spark2.1.0

現象

繼續上一章,利用effective_time字段進行重新分區導致了任務執行的傾斜
上一章的數據傾斜
本章就要針對這個問題進行處理。

問題定位

首先看下repartition是如何進行重分區的。
repartition
由partitionExprs.map(_.expr)可以得知,代碼根據列最終返回的key進行map分區,而根據接口註釋,可以得知,該接口根據傳入partitionExprs將數據重新進行map劃分到numPartitions個分區中,這效果類似於hivesql 中的distribute by。

Returns a new Dataset partitioned by the given partitioning expressions into `numPartitions`. The resulting Dataset is hash partitioned.
This is the same operation as "DISTRIBUTE BY" in SQL (Hive QL).

hive利用 Distribute By將相同key劃分到同一分區下

Hive uses the columns in Distribute By to distribute the rows among reducers. All rows with the same Distribute By columns will go to the same reducer. However, Distribute By does not guarantee clustering or sorting properties on the distributed keys.

這就回到了分區的劃分字段effective_time上來。統計一下該字段的數據分佈情況
月劃分1
月劃分2
可以看到,各月份之間的數據非常不均勻,差距在10W級別,而且null值數據達到了1000多萬條,一開始我直接把null設置爲了2020年1月,顯然是人爲造成了數據傾斜,這個時候就需要對劃分依據進行調整。

解決方式

一、使用固定分區大小
直接指定固定的分區大小,DataSet的repartition根據hashRepartition會將記錄直接分佈到指定數量的分區中。
分佈1
總用時
可以看到task分配相對均衡,總用時也由30分鐘縮短到了26分鐘。

二、根據列動態劃分,調整業務列,直接使用oracle的rownum。因爲repartitionByRange使用rangeRepartition自spark 2.3.0起才支持,這裏使用的依舊是hash分區。使用rownum的話,總數5000萬條記錄被劃分到N個分區中,只要n遠遠小於總數記錄,這個時候的劃分理論上還是比較平均的。
效果相同

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章