19
2021
01

导致数据倾斜的原因有哪些,有什么解决的方案?

什么是数据倾斜?

数据倾斜就是数据的分布不平衡,某些地方特别多,某些地方又特别少,导致的在处理数据的时候,有些很快就处理完了,而有些又迟迟未能处理完,导致整体任务最终迟迟无法完成,这种现象就是数据倾斜。


针对mapreduce的过程来说就是,有多个reduce,其中有一个或者若干个reduce要处理的数据量特别大,而其他的reduce处理的数据量则比较小,那么这些数据量小的reduce很快就可以完成,而数据量大的则需要很多时间,导致整个任务一直在等它而迟迟无法完成。

跑mr任务时常见的reduce的进度总是卡在99%,这种现象很大可能就是数据倾斜造成的。


造成数据倾斜的原因

比如某些业务数据作为key的字段本就很集中,那么结果肯定会导致数据倾斜啊。

还有其他的一些原因,但是,根本原因还是key的分布不均匀,而其他的原因就是会造成key不均匀,进而导致数据倾斜的后果,所以说根本原因是key的分布不均匀。


既然有数据倾斜这种现象,就必须要有数据倾斜对应的处理方案啊。

简单地说数据倾斜这种现象导致的任务迟迟不能完成,耗费了太多时间,极大地影响了性能,所以我们数据倾斜的解决方案设计思路就是往如何提高性能,即如何缩短任务的处理时间这方面考虑的,而要提高性能,就要让key分布相对均衡,所以我们的终极目标就是考虑如何预处理数据才能够使得它的key分布均匀。


你是如何发现Hive数据倾斜?

通过 yarn 监控平台的 task 信息查看到有个别的 task 执行时间过于缓慢,甚至还会挂掉。


解决办法

1 合理设置Map数

1) 通常情况下,作业会通过input的目录产生一个或者多个map任务。


主要的决定因素有:input的文件总个数,input的文件大小,集群设置的文件块大小。


举例:

a)  假设input目录下有1个文件a,大小为780M,那么hadoop会将该文件a分隔成7个块(6个128m的块和1个12m的块),从而产生7个map数。

b) 假设input目录下有3个文件a,b,c大小分别为10m,20m,150m,那么hadoop会分隔成4个块(10m,20m,128m,22m),从而产生4个map数。即,如果文件大于块大小(128m),那么会拆分,如果小于块大小,则把该文件当成一个块。



2) 是不是map数越多越好?


  答案是否定的。如果一个任务有很多小文件(远远小于块大小128m),则每个小文件也会被当做一个块,用一个map任务来完成,而一个map任务启动和初始化的时间远远大于逻辑处理的时间,就会造成很大的资源浪费。而且,同时可执行的map数是受限的。


3) 是不是保证每个map处理接近128m的文件块,就高枕无忧了?


答案也是不一定。比如有一个127m的文件,正常会用一个map去完成,但这个文件只有一个或者两个小字段,却有几千万的记录,如果map处理的逻辑比较复杂,用一个map任务去做,肯定也比较耗时。


针对上面的问题2和3,我们需要采取两种方式来解决:即减少map数和增加map数;



2 小文件合并

在map执行前合并小文件,减少map数:


CombineHiveInputFormat 具有对小文件进行合并的功能(系统默认的格式)


set mapred.max.split.size=112345600;

set mapred.min.split.size.per.node=112345600;

set mapred.min.split.size.per.rack=112345600;

set hive.input.format= org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;


这个参数表示执行前进行小文件合并,前面三个参数确定合并文件块的大小,大于文件块大小128m的,按照128m来分隔,小于128m,大于100m的,按照100m来分隔,把那些小于100m的(包括小文件和分隔大文件剩下的),进行合并。


3 复杂文件增加Map数

当input的文件都很大,任务逻辑复杂,map执行非常慢的时候,可以考虑增加Map数,来使得每个map处理的数据量减少,从而提高任务的执行效率。


增加map的方法为


根据 computeSliteSize(Math.max(minSize,Math.min(maxSize,blocksize)))公式

调整maxSize最大值。让maxSize最大值低于blocksize就可以增加map的个数。

mapreduce.input.fileinputformat.split.minsize=1 默认值为1


mapreduce.input.fileinputformat.split.maxsize=Long.MAXValue 默认值Long.MAXValue因此,默认情况下,切片大小=blocksize 


maxsize(切片最大值): 参数如果调到比blocksize小,则会让切片变小,而且就等于配置的这个参数的值。


minsize(切片最小值): 参数调的比blockSize大,则可以让切片变得比blocksize还大。



例如

--设置maxsize大小为10M,也就是说一个fileSplit的大小为10M

set mapreduce.input.fileinputformat.split.maxsize=10485760;


4 合理设置Reduce数

1、调整reduce个数方法一


1)每个Reduce处理的数据量默认是256MB


set hive.exec.reducers.bytes.per.reducer=256000000;


2)每个任务最大的reduce数,默认为1009


set hive.exec.reducers.max=1009;


3)计算reducer数的公式


N=min(参数2,总输入数据量/参数1)


2、调整reduce个数方法二


--设置每一个job中reduce个数

set mapreduce.job.reduces=3;


3、reduce个数并不是越多越好


过多的启动和初始化reduce也会消耗时间和资源;


同时过多的reduce会生成很多个文件,也有可能出现小文件问题


总的来说就是,数据倾斜的根源是key分布不均匀,所以应对方案要么是从源头解决(不让数据分区,直接在map端搞定),要么就是在分区时将这些集中却无效的key过滤(清洗)掉,或者是想办法将这些key打乱(给key加上标签),让它们进入到不同的reduce中。

« 上一篇 下一篇 »

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。