Q3:数据倾斜系列
    _
    Q3.1:
    什么是数据倾斜?
    由于数据分布不均匀,造成数据大量的集中到一点,造成数据热点。
    具体表现为在执行任务的时候,任务进度长时间维持在99%左右,查看任务监控页面,发现只有少量(1个或几个)reduce子任务未完成。因为其处理的数据量和其他reduce差异过大。

    单一reduce的记录数与平均记录数差异过大,通常可能达到3倍甚至更多。最长时长远大于平均时长。
    可以形象的理解为现在有一堆砖要搬,但是分配任务的时候某个(机器)人1个人接收到了自己要搬10万块转,但是其他人都是几百块转顶多上千块转,最后导致砖一直没搬完,工程进度搁置。
    ————————————
    Q3.2 数据倾斜产生的原因?
    通过之前的初识Hadoop和初识hive我们知道
    在执行Hive SQL语句的过程中会经历Map和Reduce两个步骤,
    下面通过统计单词出现的次数来举例说明:
    如图所示:

    image.png
    可以看到,Map过程会将原始数据转换成类似于(hello,1)这样的键值对,然后Reduce过程会对具有相同key的数据进行合并计算。
    在默认情况下,具有相同key的数据会被放在同一个Reduce任务中,因此就会出现一个人累死,其他人闲死的情况,即出现数据倾斜的问题。

    在执行Hive SQL语句或者运行MapReduce作业时如果一直卡在Map100%,Reduce99%,一般就是遇到了数据倾斜的问题。
    上面只是数据倾斜发生的一种可能,大致来讲,数据倾斜发生的原因一般为以下情况
    1)、key分布不均匀(如上图例子)
    2)、业务数据本身的特性
    3)、建表时考虑不周
    4)、某些SQL语句本身就有数据倾斜
    __
    Q3.3:数据倾斜的解决方案?
    A:
    1)
    当使用group by分组时,如果某些key占比非常大,由于相同key的数据会被拉取到相同节点中执行Reduce操作,因此会出现某些节点需要计算的数据量远大于其他节点的情况,造成数据倾斜。最明显的特征是在Reduce任务执行时,进度停留在99%的时间非常长,此时1%的节点计算量甚至可能超过其余99%节点计算量的总和。

    通过设置“set hive.map.aggr=true”和“set hive.groupby.skewindata=true”参数可以有效规避这个问题。

    此时生成的查询会将此前的一个MapReduce作业拆分成两个任务。

    • 在第一个任务中,Map任务的输出结果结合会随机分布到Reduce任务中,每个Reduce任务进行部分聚合操作,并输出结果,这样相同key的数据会被拉取到不同的节点中,从而答达到负载均衡的目的。
    • 第二个任务根据第一个任务预处理的数据结果将相同key数据分发到同一个Reduce任务中,完成最终的聚合操作。

    2)
    当Map任务的计算量非常大,如执行count()、sum(case when…),等语句时,需要设置Map任务数量的上限,可以通过“set mapred.map.tasks”这条语句设置合理的Map任务数量。
    3)
    如果Hive SQL 语句中计算的数据量非常大,例如下面的语句:
    select a,
    count(distinct b)from t
    group by a
    此时就会因为count(distinct b)函数而出现数据倾斜的问题,可以使用“sum…group by”代替该函数,例如:
    select a,
    sum(1) from
    (select a,
    b from t
    group by a,b)
    group by a
    4)
    当需要只想join操作但是关键字字段存在大量空置时,则可以在join操作过程中忽略空值,然后再通过union操作加上空值。
    如:
    select

    from log a
    join users b ona.id=b.id
    where a.id is not null
    union all
    select * from log a
    where a.id is null