6.4.4 減小數據傾斜的性能損失
數據傾斜是數據中的常見情況。數據中不可避免地會出現離群值(outlier),並導致數據傾斜。這些離群值會顯著地拖慢MapReduce的執行。常見的數據傾斜有以下幾類:
- 數據頻率傾斜——某一個區域的數據量要遠遠大於其他區域。
- 數據大小傾斜——部分記錄的大小遠遠大於平均值。
在map端和reduce端都有可能發生數據傾斜。在map端的數據傾斜會讓多樣化的數據集的處理效率更低。在reduce端的數據傾斜常常來源於MapReduce的默認分區器。
數據傾斜會導致map和reduce的任務執行時間大為延長,也會讓需要緩存數據集的操作消耗更多的內存資源。
前面6.2.2和6.2.3中的技術29和34介紹了如何診斷是否存在數據傾斜。這一節中將介紹如何確定傾斜的數據,如何緩解它們的影響。
技術50 收集傾斜數據
本技術將關注由map的輸出數據中的數據頻率傾斜的問題。
問題
需要診斷map輸出中哪些鍵存在數據傾斜。
方案
在reduce方法中加入記錄map輸出鍵的詳細情況的功能。
討論
在發現了傾斜數據的存在之后,就很有必要診斷造成數據傾斜的那些鍵。有一個簡便方法就是在代碼里實現追蹤每個鍵的最大值。為了減少追蹤量,可以設置數據量閥值,只追蹤那些數據量大於閥值的鍵,並輸出到日志中。實現代碼如下。
1 public static final String MAX_VALUES = "skew.maxvalues"; 2 private int maxValueThreshold; 3 4 @Override 5 public void configure(JobConf job) { 6 maxValueThreshold = job.getInt(MAX_VALUES, 100); 7 } 8 9 @Override 10 public void reduce(Text key, Iterator<Text> values, 11 OutputCollector<Text, Text> output, 12 Reporter reporter) throws IOException { 13 14 int i = 0; 15 16 while (values.hasNext()) { 17 values.next(); 18 i++; 19 } 20 21 if (++i > maxValueThreshold) { 22 log.info("Received " + i + " values for key " + key); 23 } 24 }
運行作業后就可以從日志中判斷發生傾斜的鍵以及傾斜程度。
小結
跟蹤傾斜數據是了解數據的重要一步,也是設計MapReduce作業的重要基礎。
下一步介紹如何減小Reduce數據傾斜的性能損失了。
技術51 減小Reduce端數據傾斜的性能損失
Reduce數據傾斜一般是指map的輸出數據中存在數據頻率傾斜的狀況,也就是部分輸出鍵的數據量遠遠大於其它的輸出鍵。
問題
需要減小reduce端數據傾斜的性能損失。
討論
用一系列的方法減小數據傾斜的風險,例如使用自定義的分區器,使用map端連接等。
方案
在這個方案中將討論多個減輕reduce數據傾斜的性能損失的方法。
方法1:抽樣和范圍分區
Hadoop默認的分區器是基於map輸出鍵的哈希值分區。這僅在數據分布比較均勻時比較好。在有數據傾斜時就很有問題。
使用分區器需要首先了解數據的特性。在第4章的TotalOrderPartitioner中,可以通過對原始數據進行抽樣得到的結果集來預設分區邊界值。TotalOrderPartitioner中的范圍分區器可以通過預設的分區邊界值進行分區。因此它也可以很好地用在矯正數據中的部分鍵的數據傾斜問題。
方法2:自定義分區
另一個抽樣和范圍分區的替代方案是基於輸出鍵的背景知識進行自定義分區。例如,如果map輸出鍵的單詞來源於一本書。其中大部分必然是省略詞(stopword)。那么就可以將自定義分區將這部分省略詞發送給固定的一部分reduce實例。而將其他的都發送給剩余的reduce實例。
方法3:Combine
使用Combine可以大量地減小數據頻率傾斜和數據大小傾斜。在可能的情況下,combine的目的就是聚合並精簡數據。在技術48種介紹了combine。
方法4:Map端連接和半連接
如果連接的數據集太大而不能在map端的連接中使用。那么可以考慮第4章和第7章中介紹的超大數據集的連接優化方案。
方法5:數據大小傾斜的自定義策略
在map端或reduce端的數據大小傾斜都會對緩存造成較大的影響,乃至導致OutOfMemoryError異常。處理這種情況並不容易。可以參考以下方法。
- 設置mapred.linerecordreader.maxlength來限制RecordReader讀取的最大長度。RecordReader在TextInputFormat和KeyValueTextInputFormat類中使用。默認長度沒有上限。
- 通過org.apache.hadoop.contrib.utils.join設置緩存的數據集的記錄數上限。在reduce中默認的緩存記錄數上限是100條。
- 考慮使用有損數據結構壓縮數據,如Bloom過濾器。這將在第7章介紹。
小結
下一部分將介紹如何用戶代碼中對性能影響較大的情況,以及相應的優化方案。