如何解决 MapReduce 数据倾斜的问题?

前言

本文隶属于专栏《1000个问题搞定大数据技术体系》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢!

本专栏目录结构和参考文献请见1000个问题搞定大数据技术体系

正文

在这里插入图片描述

什么是数据倾斜?

数据倾斜是数据中的常见情况。

数据中不可避免地会出现离群值(outlier),并导致数据倾斜。

这些离群值会显著地拖慢 MapReduce 的执行。

常见的数据倾斜有以下几类

  1. 数据频率倾斜——某一个区域的数据量要远远大于其他区域。
  2. 数据大小倾斜——部分记录的大小远远大于平均值。

MapReduce 数据倾斜可能的原因

在 map 端和 reduce 端都有可能发生数据倾斜。

在 map 端的数据倾斜会让多样化的数据集的处理效率更低。

在 reduce 端的数据倾斜常常来源于 MapReduce 的默认分区器。

MapReduce 数据倾斜可能导致的后果

数据倾斜会导致 map 和 reduce 的任务执行时间大为延长,也会让需要缓存数据集的操作消耗更多的内存资源。

如何诊断是否存在数据倾斜

在 reduce 方法中加入记录 map 输出键的详细情况的功能

在发现了倾斜数据的存在之后,就很有必要诊断造成数据倾斜的那些键。

有一个简便方法就是在代码里实现追踪每个键的最大值。为了减少追踪量,可以设置数据量阀值,只追踪那些数据量大于阀值的键,并输出到日志中。实现代码如下

package com.shockang.study.bigdata.mapreduce;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;
import java.util.Iterator;

public class WordCountReducerWithDataSkew extends Reducer<Text, IntWritable, Text, IntWritable> {

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

    @Override
    protected void setup(Context context) throws IOException, InterruptedException {
        Configuration conf = context.getConfiguration();
        maxValueThreshold = Integer.parseInt(conf.get(MAX_VALUES));
    }

    /*
            key: hello
            value: List(1, 1, ...)
        */
    protected void reduce(Text key, Iterable<IntWritable> values,
                          Context context) throws IOException, InterruptedException {
        int i = 0;
        for (IntWritable value : values) {
            System.out.println(value);
            i++;
        }

        if (++i > maxValueThreshold) {
            System.out.println("Received " + i + " values for key " + key);
        }
    }
}

运行作业后就可以从日志中判断发生倾斜的键以及倾斜程度

跟踪倾斜数据是了解数据的重要一步,也是设计 MapReduce 作业的重要基础

减缓 Reduce 端数据倾斜的常规手段

  1. 抽样和范围分区
    Hadoop 默认的分区器是基于 map 输出键的哈希值分区。这仅在数据分布比较均匀时比较好。在有数据倾斜时就很有问题。
    使用分区器需要首先了解数据的特性。可以通过对原始数据进行抽样得到的结果集来预设分区边界值。范围分区器可以通过预设的分区边界值进行分区。因此它也可以很好地用在矫正数据中的部分键的数据倾斜问题。
  2. 自定义分区
    另一个抽样和范围分区的替代方案是基于输出键的背景知识进行自定义分区。例如,如果map输出键的单词来源于一本书。其中大部分必然是省略词(stopword)。
    那么就可以将自定义分区将这部分省略词发送给固定的一部分 reduce 实例。而将其他的都发送给剩余的 reduce 实例。
  3. Combine
    使用 Combine 可以大量地减小数据频率倾斜和数据大小倾斜。在可能的情况下,combine 的目的就是聚合并精简数据。
  4. Map 端连接和半连接
    尽可能在 map 端就进行数据关联,避免进行 Shuffle。
  5. 数据大小倾斜的自定义策略
  • 设置 mapred.linerecordreader.maxlength 来限制 RecordReader 读取的最大长度。RecordReader 在 TextInputFormat 和 KeyValueTextInputFormat 类中使用。默认长度没有上限。
  • 通过 org.apache.hadoop.contrib.utils.join 设置缓存的数据集的记录数上限。在 reduce 中默认的缓存记录数上限是 100 条。
  • 考虑使用有损数据结构压缩数据,如Bloom过滤器。
  • 15
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
MapReduce数据倾斜是指在MapReduce任务中,某些Map任务处理的数据量远远超过其他Map任务,导致整个任务的效率降低。数据倾斜问题MapReduce中常见的性能瓶颈之一。以下是解决MapReduce数据倾斜问题的几种方法: 1. 均匀划分数据:在MapReduce任务中,数据均匀划分是防止数据倾斜的最有效的方法之一。可以通过对数据进行采样,来确定数据均匀划分的划分点。 2. Combiner函数:Combiner函数可以在Map阶段对数据进行合并处理,减少Map输出数据量,从而降低Reduce任务的负担。可以在Combiner函数中对于一些key进行合并处理,减少数据倾斜。 3. 调整Reduce任务数量:当Reduce任务的数量过少时,会导致某些Reduce任务的数据处理量过大,从而产生数据倾斜。可以通过增加Reduce任务的数量来解决这个问题。 4. 增加Map任务数量:增加Map任务的数量,可以将数据均匀地分散到更多的Map任务中去,从而减少数据倾斜。 5. 动态调整Map任务输入数据:可以根据Map任务处理的数据量来动态调整数据的输入,将处理量较大的数据均匀分散到多个Map任务中。可以通过自定义InputFormat来实现这个功能。 6. 使用随机数进行分桶:将数据随机分配到多个桶中,通过增加桶的数量来增加Map任务的数量,从而将数据均匀分散到多个Map任务中。这个方法需要保证随机数分配的均匀性。
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值