hadoop 數據傾斜

          數據傾斜是數據中的常見情況。數據中不可避免地會出現離羣值(outlier),並導致數據傾斜。這些離羣值會顯著地拖慢MapReduce的執行。常見的數據傾斜有以下幾類:

  1. 數據頻率傾斜——某一個區域的數據量要遠遠大於其他區域。
  2. 數據大小傾斜——部分記錄的大小遠遠大於平均值。

在map端和reduce端都有可能發生數據傾斜。在map端的數據傾斜會讓多樣化的數據集的處理效率更低。在reduce端的數據傾斜常常來源於MapReduce的默認分區器。


在發現了傾斜數據的存在之後,就很有必要診斷造成數據傾斜的那些鍵。有一個簡便方法就是在代碼裏實現追蹤每個鍵的最大值。爲了減少追蹤量,可以設置數據量閥值,只追蹤那些數據量大於閥值的鍵,並輸出到日誌中。實現代碼如下。


public static final String MAX_VALUES = "skew.maxvalues";
private int maxValueThreshold;


@Override
public void configure(JobConf job) {
    maxValueThreshold = job.getInt(MAX_VALUES, 100);
}


@Override
public void reduce(Text key, Iterator<Text> values,
                    OutputCollector<Text, Text> output, 
                    Reporter reporter) throws IOException {
                    
    int i = 0;
    
    while (values.hasNext()) {
        values.next();
        i++;
    }
    
    if (++i > maxValueThreshold) {
        log.info("Received " + i + " values for key " + key);
    }
}



方案

在這個方案中將討論多個減輕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章介紹。

 


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