Hive千亿级数据倾斜解决方案

大数据 2023-07-05 17:29:38
48阅读

文中转载微信公众平台「五分钟学互联网大数据」,创作者园陌 。转截文中请联络五分钟学互联网大数据微信公众号。

数据倾斜难题分析

数据倾斜是分布式架构难以避免的难题,一切分布式架构都是有概率产生数据倾斜,但有一些小伙伴们在平常工作上认知并不是很显著。这儿要留意这篇文章内容的文章标题—“千亿元级数据信息”,为什么说千亿元级,由于假如一个每日任务的信息量仅有上百万,它即便发生了数据倾斜,全部数据信息都跑到一台设备去实行,针对上百万的信息量,一台设备实行起來或是没什么工作压力的,这时候数据倾斜对大家认知并不大,仅有数据信息做到一个数量级时,一台设备应付账款不上这么多数据信息,这时候假如产生数据倾斜,最终就难以算出結果。

因此 就必须大家对数据倾斜的难题开展提升,尽量减少或缓解数据倾斜产生的危害。

在处理数据倾斜难题以前,也要再提一句:沒有短板时讨论提升,全是怨天尤人。

大伙儿想一想,在map和reduce两个阶段中,最非常容易发生数据倾斜的便是reduce环节,由于map到reduce会历经shuffle环节,在shuffle中默认设置会依照key开展hash,假如同样的key太多,那麼hash的結果便是很多同样的key进到到同一个reduce中,造成 数据倾斜。

那麼是否有很有可能在map环节就产生数据倾斜呢,是有这类很有可能的。

一个每日任务中,数据库文件在进到map环节以前会开展分割,默认设置是128M一个数据信息块,可是假如当对文档应用GZIP缩小等不兼容文件分割实际操作的压缩方式时,MR每日任务载入缩小后的文档时,是对它分割不上的,该压缩包总是被一个每日任务所载入,假如有一个超大型的不能分割的压缩包被一个map载入时,便会产生map环节的数据倾斜。

因此 ,从实质上而言,产生数据倾斜的缘故有二种:一是每日任务中必须解决很多同样的key的数据信息。二是每日任务载入不可缺少的大文件。

数据倾斜解决方法

MapReduce和Spark中的数据倾斜解决方法基本原理全是相近的,下列探讨Hive应用MapReduce模块引起的数据倾斜,Spark数据倾斜还可以此为参考。

1. 空值引起的数据倾斜

具体业务流程中有一些很多的null值或是一些无意义的数据信息参加到测算工作中,表格中有很多的null值,假如表中间开展join实际操作,便会有shuffle造成,那样全部的null值都是会被分派到一个reduce中,必定造成数据倾斜。

以前有小伙伴们问,假如A、B两表join实际操作,倘若A表格中必须join的字段名为null,可是B表格中必须join的字段名不以null,这两个字段名压根就join不上啊,为何还会继续放进一个reduce中呢?

这儿大家必须确立一个定义,数据信息放进同一个reduce中的缘故并不是由于字段名能否join上,只是由于shuffle环节的hash实际操作,只需key的hash結果是一样的,他们便会被拖到同一个reduce中。

解决方法:

第一种:能够立即不许null值参加join实际操作,即不许null值有shuffle环节

 
  1. SELECT * 
  2. FROM log a 
  3.  JOIN users b 
  4.  ON a.user_id IS NOT NULL 
  5.   AND a.user_id = b.user_id 
  6. UNION ALL 
  7. SELECT * 
  8. FROM log a 
  9. WHERE a.user_id IS NULL

第二种:由于null值参加shuffle时的hash結果是一样的,那麼我们可以给null值任意取值,那样他们的hash結果就不一样,便会进到不一样的reduce中:

 
  1. SELECT * 
  2. FROM log a 
  3.  LEFT JOIN users b ON CASE  
  4.    WHEN a.user_id IS NULL THEN concat('hive_', rand()) 
  5.    ELSE a.user_id 
  6.   END = b.user_id; 

2. 不一样基本数据类型引起的数据倾斜

针对2个表join,表a中必须join的字段名key为int,表b中key字段名不仅有string种类也是有int种类。当依照key开展2个表的join实际操作时,默认设置的Hash实际操作会按int型的id来开展分派,那样全部的string种类都被分派成同一个id,結果便是全部的string种类的字段名进到到一个reduce中,引起数据倾斜。

解决方法:

假如key字段名不仅有string种类也是有int类型,默认设置的hash就都是会按int类型来分派,那大家立即把int类型都变为string就好了,那样key字段名都为string,hash时就依照string种类分派了:

 
  1. SELECT * 
  2. FROM users a 
  3.  LEFT JOIN logs b ON a.usr_id = CAST(b.user_id AS string); 

3. 不能分拆大文件引起的数据倾斜

当群集的信息量提高到一定经营规模,有一些数据信息必须存档或是数据归档,此刻通常会对数据信息开展缩小;当对文档应用GZIP缩小等不兼容文件分割实际操作的压缩方式,在日后有工作涉及到载入缩小后的文档时,该压缩包总是被一个每日任务所载入。假如该压缩包非常大,则解决该文件的Map必须耗费的時间会远超过载入一般文档的Map時间,该Map每日任务会变成工作运作的短板。这类状况也就是Map读取文件的数据倾斜。

解决方法:

这类数据倾斜难题沒有哪些好的解决方法,只有将应用GZIP缩小等不兼容文件分割的文档变为bzip和zip等适用文件分割的压缩方式。

因此 ,我们在对文档开展缩小时,为防止因不能分拆大文件而引起数据信息载入的歪斜,在数据编码的情况下能够选用bzip2和Zip等适用文件分割的压缩算法。

4. 数据信息澎涨引起的数据倾斜

在多维汇聚测算时,假如开展排序汇聚的字段名太多,以下:

select a,b,c,count(1)from log group by a,b,c with rollup;

注:针对最终的with rollup关键词不清楚大伙儿使用过没,with rollup是用于在排序数据统计的基本上再开展统计分析归纳,即用于获得group by的归纳信息内容。

假如上边的log表的信息量非常大,而且Map端汇聚不可以非常好地具有数据编码的状况下,会造成 Map端产出率的数据信息极速澎涨,这类状况非常容易造成 工作内存溢出的出现异常。假如log表带有数据倾斜key,会加重Shuffle全过程的数据倾斜。

解决方法:

能够分拆上边的sql,将with rollup拆分为以下好多个sql:

 
  1. SELECT a, b, c, COUNT(1) 
  2. FROM log 
  3. GROUP BY a, b, c; 
  4.  
  5. SELECT a, b, NULLCOUNT(1) 
  6. FROM log 
  7. GROUP BY a, b; 
  8.  
  9. SELECT a, NULLNULLCOUNT(1) 
  10. FROM log 
  11. GROUP BY a; 
  12.  
  13. SELECT NULLNULLNULLCOUNT(1) 
  14. FROM log; 

可是,上边这类方法不大好,由于现在是对3个字段名开展排序汇聚,那如果是五个或是10个字段名呢,那麼必须拆卸的SQL句子会大量。

在Hive中能够根据主要参数 hive.new.job.grouping.set.cardinality 配备的方法自动控制系统工作的拆卸,该主要参数初始值是30。表明对于grouping sets/rollups/cubes这类多维汇聚的实际操作,假如最终拆卸的键组成超过该值,会开启新的每日任务去解决超过该值以外的组成。假如在解决数据信息时,某一排序汇聚的列有很大的歪斜,能够适度调小该值。

5. 表联接时引起的数据倾斜

两表开展一般的repartition join时,假如表联接的键存有歪斜,那麼在 Shuffle 环节必定会造成数据倾斜。

解决方法:

一般作法是将歪斜的数据信息存到分布式缓存中,派发到每个Map每日任务所属连接点。在Map环节进行join实际操作,即MapJoin,这防止了 Shuffle,进而防止了数据倾斜。

MapJoin是Hive的一种提升实际操作,其适用小表JOIN大表的情景,因为表的JOIN实际操作是在Map端且在运行内存开展的,因此 其并不一定运行Reduce每日任务也就不用历经shuffle环节,进而能在一定水平上节约資源提升JOIN高效率。

在Hive 0.11版本号以前,假如想在Map环节进行join实际操作,务必应用MAPJOIN来标识表明地运行该提升实际操作,因为其必须将小表载入进运行内存因此 要留意小表的尺寸。

如将a表放进Map端运行内存中实行,在Hive 0.11版本号以前必须那样写:

 
  1. select /*  mapjoin(a) */ a.id , a.name, b.age  
  2. from a join b  
  3. on a.id = b.id; 

假如想将好几个表放进Map端运行内存中,只需在mapjoin()中写好几个表名字就可以,用分号隔开,如将a表和c表放进Map端运行内存中,则 /* mapjoin(a,c) */ 。

在Hive 0.11版本号及以后,Hive默认设置运行该提升,也就是没有必须表明的应用MAPJOIN标识,其会在必需的情况下开启该提升实际操作将一般JOIN转化成MapJoin,能够根据下列2个特性来设定该提升的开启机会:

hive.auto.convert.join=true 初始值为true,全自动打开MAPJOIN提升。

hive.mapjoin.smalltable.filesize=2500000 初始值为2500000(25M),根据配备该特性来明确应用该提升的表的尺寸,假如表的尺寸低于此值便会被载入进运行内存中。

留意:应用默认设置运行该提升的方法假如发生无缘无故的BUG(例如MAPJOIN并失灵),就将下列2个特性置为fase手动式应用MAPJOIN标识来运行该提升:

hive.auto.convert.join=false (关掉全自动MAPJOIN变换实际操作)

hive.ignore.mapjoin.hint=false (不忽视MAPJOIN标识)

再提一句:将表放进Map端运行内存时,假如连接点的运行内存非常大,但或是发生内存溢出的状况,我们可以根据这一主要参数 mapreduce.map.memory.mb 调整Map端运行内存的尺寸。

6. 的确没法降低信息量引起的数据倾斜

在一些实际操作中,大家没有办法降低信息量,如在应用 collect_list 涵数时:

 
  1. select s_age,collect_list(s_score) list_score 
  2. from student 
  3. group by s_age 

collect_list:将排序中的某列变为一个二维数组回到。

在以上sql中,s_age假如存有数据倾斜,当信息量大到一定的总数,会造成 解决歪斜的reduce每日任务造成内存溢出的出现异常。

注:collect_list輸出一个二维数组,正中间結果会放进运行内存中,因此 假如collect_list汇聚过多数据信息,会造成 内存溢出。

有小伙伴们说它是 group by 排序造成的数据倾斜,能够打开hive.groupby.skewindata主要参数来提升。大家下面剖析下:

打开该配备会将工作拆卸成2个工作,第一个工作会尽量将Map的数据信息平分到Reduce环节,并在这个环节完成数据信息的预汇聚,以降低第二个作业处理的信息量;第二个工作在第一个作业处理的数据信息基本上开展結果的汇聚。

hive.groupby.skewindata的带头作用取决于转化成的第一个工作可以合理降低总数。可是针对collect_list这类规定全量实际操作全部数据信息的正中间結果的涵数而言,显著起不上功效,反倒由于引进新的工作提升了硬盘和互联网I/O的压力,而造成 特性越来越更加不高。

解决方法:

这类难题最立即的方法便是调节reduce所实行的内存空间。

调节reduce的内存空间应用mapreduce.reduce.memory.mb这一配备。

【责编:武晓燕 TEL:(010)68476606】
关注点赞 0
the end
免责声明:本文不代表本站的观点和立场,如有侵权请联系本站删除!本站仅提供信息存储空间服务。