前言

南国在最开始学习Hadoop的时候,一直其他人说的数据倾斜及数据倾斜的解决办法没有完全弄明白。通过这段时间的学习,看了许多资料,这里参考网上资料 以及自己的理解。这篇博客 写一个有关于数据倾斜的归纳总结。话不多说,干货马上送到。。。

数据倾斜的定义

在弄清什么是数据倾斜之前,我想让大家看看数据分布的概念:
正常的数据分布理论上都是倾斜的,就是我们所说的20-80原理:80%的财富集中在20%的人手中, 80%的用户只使用20%的功能 , 20%的用户贡献了80%的访问量 , 不同的数据字段可能的

数据倾斜一般有两种情况:

  • 一种是唯一值非常少,极少数值有非常多的记录值(唯一值少于几千)
  • 一种是唯一值比较多,这个字段的某些值有远远多于其他值的记录数,但是它的占比也小于百分之一或千分之一

数据倾斜在MapReduce编程模型中十分常见,它是key分布不均匀,导致分发到不同的reduce上,个别reduce任务特别重,导致其他reduce都完成,而这些个别的reduce迟迟不完成的情况。用最通俗易懂的话来说,数据倾斜无非就是大量的相同key被partition分配到一个分区里,造成了’一个人累死,其他人闲死’的情况,这种情况是我们不能接受的,这也违背了并行计算的初衷,首先一个节点要承受着巨大的压力,而其他节点计算完毕后要一直等待这个忙碌的节点,也拖累了整体的计算时间,可以说效率是十分低下的。

在map端和reduce端都有可能发生数据倾斜。在map端的数据倾斜会让多样化的数据集的处理效率更低。在reduce端的数据倾斜常常来源于MapReduce的默认分区器。

分区:

常见的mapreduce分区方式为hash 和range ,
hash partition 的好处是比较弹性,跟数据类型无关,实现简单(设定reduce个数就好,一般不需要自己实现)
range partition 需要实现者自己了解数据分布, 有时候需要手工做sample取样. 同时也不够弹性, 表现在几个方面,

  1. 对同一个表的不同字段都需要实现不同的range partition, 对于时间这种字段根据查询类型的不同或者过滤条件的不同切分range 的大小都不一定.
  2. 有时候可能设计使用多个字段组合的情况, 这时候又不能使用之前单个字段的partition 类, 并且多个字段组合之间有可能有隐含的联系,比如出生日期和星座,商品和季节.
  3. 手工做sample 非常耗时间,需要使用者对查询使用的数据集的分布有领域知识.
  4. 分配方式是死的,reduce 个数是确定的,一旦某种情况下发生倾斜,调整参数

其他的分区类型还有hbase 的hregionpartitioner 或者totalorder partitioner 等.

数据倾斜的原因

发生数据倾斜的原因有:

  • key分布不均匀。
  • map端数据倾斜,输入文件太多且大小不一 。
  • reduce端数据倾斜,分区器问题。
  • 业务数据本身的特征。

数据倾斜的解决办法

解决方案:

  • 1.增加jvm内存,这适用于第一种情况(唯一值非常少,极少数值有非常多的记录值(唯一值少于几千)),这种情况下,往往只能通过硬件的手段来进行调优,增加jvm内存可以显著的提高运行效率。
  • 2.增加reduce的个数,这适用于第二种情况(唯一值比较多,这个字段的某些值有远远多于其他值的记录数,但是它的占比也小于百分之一或千分之一),我们知道,这种情况下,最容易造成的结果就是大量相同key被partition到一个分区,从而一个reduce执行了大量的工作,而如果我们增加了reduce的个数,这种情况相对来说会减轻很多,毕竟计算的节点多了,就算工作量还是不均匀的,那也要小很多。
  • 3.自定义分区,这需要用户自己继承partition类,指定分区策略,这种方式效果比较显著。
  • 4.重新设计key,有一种方案是在map阶段时给key加上一个随机数,有了随机数的key就不会被大量的分配到同一节点(小几率),待到reduce后再把随机数去掉即可。
  • 5.使用combinner合并,combinner是在map阶段,reduce之前的一个中间阶段,在这个阶段可以选择性的把大量的相同key数据先进行一个合并,可以看做是local reduce,然后再交给reduce来处理,这样做的好处很多,即减轻了map端向reduce端发送的数据量(减轻了网络带宽),也减轻了map端和reduce端中间的shuffle阶段的数据拉取数量(本地化磁盘IO速率),推荐使用这种方法。

总结

注意:数据倾斜没有一劳永逸的方式可以解决,了解你的数据集的分布情况,然后了解你所使用计算框架的运行机制和瓶颈,针对特定的情况做特定的优化,做多种尝试,观察是否有效.