hive 优化(二)

在讨论hive优化之前,我们需要知道的是HQL它的执行过程。

简单的说,HQL会最终转化为job,然后通过MR来执行job

 

问题一 既然HQL会转化为JOB,那么如果job数量太多,会不会对hive执行带来性能的影响?

我们知道客户端提交JOB到YARN集群,然后MRAppMaster则会创建JOB,并对JOB进行初始化,初始化JOB是需要好费时间的,因为在这里会根据文件创建分片,然后决定Mapper数量等,还要创建MapTask和ReduceTask,如果JOB太多,肯定会对hive性能有影响的

 

 

YARN在初始化JOB的时候,是需要耗时的

问题二 既然最终是通过MR来运行JOB,那么MR本身是否存在着隐式的性能问题,比如Map数量太多或者Reduce数量太多会不会带来影响,数据倾斜怎么办?

Mapper数量太多:会产生大量的文件,如果这些文件还是小文件,那么就有调优的可能,因为我们知道创建和初始化和启动Mapper是需要很大开销的,一个Mapper任务就是一个jvm进程。

还有个问题就是Mapper数量太多,那么Suffle过程所耗费的网络1/O和磁盘I/O很大,还会涉及到排序,所以Mapper数量过多并不是一个好事

Mapper数量太太少:如果文件过大,Mapper数量太少,那么文件处理的并发度肯定就不好,JOB需要执行的时间就长。

 

Reducer数量太多:我们知道一个Reducer就对应一个输出,如果这些是小文件,那么其他job依赖这个job的结果,那么又是很多小文件;另外初始化和启动Reducer同Mapper一样,也会有很大的开销

 

Reducer数量太少: 如果只需跑Map任务,没啥影响,如果数据量很大,Reducer数量太少,并发度不高,执行耗时;而且数据倾斜的可能性很大

 

那我们带着问题来探讨hive的优化过程及方式。

一 设计层面的优化措施

一般而言,我们使用Hive的时候都会预先估计到hive的数据量大概有多少,如果是大量的数据的话,我们应该提前在设计或者架构层面做好一些优化措施:

1.1分区

合理设计表分区,是一个很不错的优化措施,因为这样,我们就可以避免全表扫描,而在过滤的时候只针对对应分区的数据扫描。

 

1.2使用列式存储格式和开启压缩

一般来讲,列式存储我们在查询的时候,可以跳过不必要查询的列,不会把所有列都查询出来,并且他自己有着高效的压缩率,既节省空间也节省内存和CPU

1.3尽量使用宽表代表嵌套表

 

1.4如果有JOIN场景,应该考虑表的具体情况,选择合适的JOJN方式:

如果都是小表:可以使用普通的JOIN方式,即ReduceSide JOIN

如果一个是小表,一个是大表:

理论上小表取决于hive.mapjoin.smalltable.filesize设置的值为准,取决于自己的业务也可以自己设置这个值,我们是可以只进行MapSide Join,而不用去做Reduce,这样就可以节省shuffle过程的耗费资源的操作,这个一般小表放在JOIN左边,大表放在右边,因为会把左边的表读取出来放到内存,然后通过DistributedCache缓存到各个节点

如果都是大表:那么对表我们可以进行合适的分桶,2张表都需要对参与JOIN的key进行分桶,桶数可以一样,也可以不一样,但是不一样也是有前提的,大表需要是小表的倍数,即必须保证他们相同的key都分到相同的桶里面去了

另外JOIN一定要避免笛卡尔积,在hive中,数据量有很大的情况下,这可能回带来灾难
注意:表连接不是小表数据量少就放在JOIN左边,而是说应该JOIN的key重复值少的应该放在左边

 

 

二 配置参数的优化

2.1设置合理的mapper数量和reducer数量

如果表很大的话,我们需要设置合理的mapper数量和reducer数量,避免设置太小,没有合理利用资源,执行时间慢;设置太大,过度消耗资源

2.1.1mapper: 很多都是小文件

我们知道一个小文件,默认小于128M,就是一个切片,就会产生一个map task。那如果小文件太多,则会造成很多的maptask;而且还会对NameNode带来压力

解决办法:合并小文件,我们可以在执行前设置这个参数:

sethive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInput

Format;

 

2.1.2mapper: 如果表本身就很大

如果文件本身就很大,我么可以改变mapper数量,在产生切片的时候,

我们可以调整切片的数量,进而调整mapper的数量。

 

每个map处理的最大的文件大小

setmapred.max.split.size=256000000;

一个节点上split的最小是多少,默认是1字节 ,决定了多个datanode上的文件是否需要合并

setmapred.min.split.size.per.node=100000000;

一个交换机下split的最小是多少,默认是1字节,决定了多个交换机上的文件是否需要合并

setmapred.min.split.size.per.rack=100000000;

注意:mapred.min.split.size.per.node和mapred.min.split.size.per.rack会带来一定的I/O消耗,因为需要合并文件

 

2.1.3Reducer 个数太多或者太少:

控制最大的reducer数量, 默认为999

hive.exec.reducers.max

这个参数控制一个job会有多少个reducer来处理,依据的是输入文件的总大小.默认1GB。

hive.exec.reducers.bytes.per.reducer

直接指定Reduce个数,如果指定hive就不会自己计算需要的Reducer个数

mapred.reduce.tasks

 

hive分配reducer个数的算法:

hive.exec.reducers.bytes.per.reducer(默认为1G)

hive.exec.reducers.max(默认为999)

min(hive.exec.reducers.max,输入文件大小/ hive.exec.reducers.bytes.per.

reducer)取这两个值中间最小的

一旦设置了mapred.reduce.tasks这个参数,那么上述算法无效,优先使用这个值的参数,默认这个值是-1

有一些情况,无论我们怎么调整,始终只有一个reduder:

#文件数据量太小,没有达到hive.exec.reducers.bytes.per.reducer这个标准

#使用了groupby然后进行汇总的功能

#使用orderby全局排序(尽量使用SORT BY,SORT BY先在每一个Reducer做局部排序,最后再起一个JOB对排好序的进行全局排序)

 

2.2map端聚合

如果为了减轻reduce端进行聚合操作的压力,我们可以在map端就进行一次reduce,也就是shuffle过程的combine操作

hive.map.aggr=true.默认就是开启的

三 对HQL语句的优化

有些时候,我们是可以针对HQL语句进行优化的。

比如我们只是查询我们需要的列等,这个就得具体问题具体分析

 

四 数据倾斜

什么是数据倾斜?

在MapReduce计算的时候,某一个key的值过度集中,导致Reduce端负载不均衡,有的Reduce很快就完看,有的Reduce要运行很长时间才能完成。一般这种情况发生在JOIN或者GROUPBY的时候

 

4.1GROUP BY 数据倾斜

解决办法:

第一种: 在map 端就进行combine,先对key进行一次聚合,这样,Reducer取数据的时候,就会减少很多。而且Reducer的时候参与计算的key也少很多

 

第二种:配置参数hive.groupby.skewindata= true

这是hive通用的数据倾斜优化方案,但是还是得结合具体的业务而定,并不一定就适合你的场景。

他的原理就是先启动一个JOB, 不按照key进行分区,然后随机分给reducer,每一个Reducer来做部分聚合操作,这样相同的groupkey就有可能分发到不同的Reducer之中,从而达到负载均衡的目的;然后再起一个JOB, 根据上一个JOB的Reduce的输出,然后按照groupkey进行聚合操作,最后完成最终的聚合操作

这样做效果也不是很明显,不推荐使用。

 

第三种:改写HQL语句

/*改写前*/ 

selecta,count(distinct b) as c from tbl group by a;

 

/*改写后*/ 

selecta,count(*) as c 

from(select distinct a, b from tbl) group by a;

 

4.2JOIN造成的数据倾斜

第一种:hive自身的优化方案skewjoin

原理就是把JOINkey加上一些随机数,将这些key打乱,然后就会在不同的节点计算;最后在启动一个JOB,以第一个作为输入源,将相同的key分发到相同的节点上处理

必要条件:

sethive.optimize.skewjoin = true;

key要达到多少才会认为是倾斜数据,然后才进行优化

sethive.skewjoin.key=1000000;

 

4.3JOIN key数据类型不同也会造成数据倾斜

将类型通过函数转换一致

 

 

其他优化案例:

Count(distinct)

l 当该字段存在大量值为null或空的记录时容易造成倾斜。

解决思路:

1) count(distinct)时,将值为空的数据在where里过滤掉,在最后结果中加1。

2)  如果还有其他计算,需要进行groupby,可以先将值为空的记录单独处理,再和其他计算结果进行union

3)  如果groupby维度过小,则可以  采用count和groupby的方式来替换count(distinct)完成计算

l 特殊情况特殊处理:

在业务逻辑优化效果不大情况下,有些时候是可以将倾斜的数据单独拿出来处理,最后union回去。

 

l  countdistinct优化:

实例1:

        优化前:

        selectcount(distinct id) from student;

        只有一个job任务,而且只有一个reduce,处理的工作量比较大。

        

优化后:

        selectcount(1) from (select distinct id from student) tmp;

        或

        selectcount(1) from (select id from student group by id) tmp;

         可以通过设置setmapred.reduce.tasks的值,加快(select distinct id from student) tmp部分的处理。

 

实例2:

优化前:

selecta,sum(b),count(distinctc),count(distinct d)

fromtest

groupby a;

优化后:

selecta,sum(b)as b,count(c) as c,count(d) as d

from(

selecta,0 as b,c,null as d from test group by a,c

unionall

selecta,0 as b,null as c,d from test group by a,d

unionall

selecta,b,null as c,null as d from test

)tmpgroup bya;

 

 

 

我们知道文件数目小,容易在文件存储端造成瓶颈,给 HDFS 带来压力,影响处理效率。对此,可以通过合并Map和Reduce的结果文件来消除这样的影响。

用于设置合并属性的参数有:

 

是否合并Map输出文件:hive.merge.mapfiles=true(默认值为真)

是否合并Reduce 端输出文件:hive.merge.mapredfiles=false(默认值为假)

合并文件的大小:hive.merge.size.per.task=256*1000*1000(默认值为256000000)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

莫言静好、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值