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 values,
                    OutputCollector 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章介绍。

 


你可能感兴趣的:(hadoop,Hadoop)