背景
對於分布式數據庫來說,QUERY的運行效率取決於最慢的那個節點。
當數據出現傾斜時,某些節點的運算量可能比其他節點大。除了帶來運行慢的問題,還有其他的問題,例如導致OOM,或者DISK FULL等問題。
如何監控傾斜
1、 監控數據庫級別傾斜
2、 監控表級傾斜
出現數據傾斜的原因和解決辦法
1、分布鍵選擇不正確,導致數據存儲分布不均。
例如選擇的字段某些值特別多,由於數據是按分布鍵VALUE的HASH進行分布的,導致這些值所在的SEGMENT的數據可能比而其他SEGMENT多很多。
分布鍵的選擇詳見:
《Greenplum 最佳實踐 - 數據分布黃金法則 - 分布列與分區的選擇》
2、查詢導致的數據重分布,數據重分布后,數據不均。
例如group by的字段不是分布鍵,那么運算時就需要重分布數據。
解決辦法1:
由於查詢帶來的數據傾斜的可能性非常大,所以Greenplum在內核層面做了優化,做法是:
先在segment本地聚合產生少量記錄,將聚合結果再次重分布,重分布后再次在segment聚合,最后將結果發到master節點,有必要的話在master節點調用聚合函數的final func(已經是很少的記錄數和運算量)。
例子:
tbl_ao_col表是c1的分布鍵,但是我們group by使用了c398字段,因此看看它是怎么做的呢?請看執行計划的解釋。
對於非分布鍵的分組聚合請求,Greenplum采用了多階段聚合如下:
第一階段,在SEGMENT本地聚合。(需要掃描所有數據,這里不同存儲,前面的列和后面的列的差別就體現出來了,行存儲的deform開銷,在對后面的列進行統計時性能影響很明顯。)
第二階段,根據分組字段,將結果數據重分布。(重分布需要用到的字段,此時結果很小。)
第三階段,再次在SEGMENT本地聚合。(需要對重分布后的數據進行聚合。)
第四階段,返回結果給master,有必要的話master節點調用聚合函數的final func(已經是很少的記錄數和運算量)。
3、內核只能解決一部分查詢引入的數據重分布傾斜問題,還有一部分問題內核沒法解決。例如窗口查詢。
使用窗口函數時,Greenplum需要先按窗口中的分組對數據進行重分布,這一次重分布就可能導致嚴重的傾斜。
實際上內核層優化才是最好的解決辦法,例如以上窗口函數,由於我們只需要取c2分組中c3最小的一條記錄。因此也可以在每個節點先取得一條,再重分布,再算。
不通過修改內核,還有什么方法呢?
3.1 Mapreduce任務就很好解決,Greenplum的mapreduce接口調用方法如下:
http://greenplum.org/docs/ref_guide/yaml_spec.html
3.2 通過寫PL函數也能解決。例如
小結
數據傾斜的原因可能是數據存儲的傾斜,QUERY執行過程中數據重分布的傾斜。
數據傾斜可能引入以下后果:
1、計算短板
2、oom
3、disk full
數據傾斜的解決辦法:
1、如果是存儲的傾斜,通過調整更加均勻的分布鍵來解決。(也可以選擇使用隨機分布,或者使用多列作為分布鍵)。
2、如果是QUERY造成的傾斜,Greenplum內核對group by已經做了優化,即使分組字段不是分布鍵,通過多階段聚合,可以消除影響。
3、如果是窗口函數QUERY造成的傾斜,目前內核沒有對這部分優化,首先會對窗口函數的分組字段所有數據進行重分布,如果這個分組字段數據有嚴重傾斜,那么會造成重分布后的某些節點數據量過大。解決辦法有mapreduce或pl函數。
參考
《Greenplum 內存與負載管理最佳實踐》
《Greenplum 最佳實踐 - 數據分布黃金法則 - 分布列與分區的選擇》