Hive性能调优相关参数整理

前言

​ 我不造数据,我只是数据的搬运工。
作为一个“大数据民工”,在做数据离线ETL时,通常会使用Hive作为我们首选工具。Hive虽然比较慢,但是在处理海量数据(GB甚至TB级数据)时,其借助于Yarn的分布式处理能力以及其稳定性,让其在大数据领域成为了一个绕不过去的话题。
​ Hive要发挥其稳定性,又要让其稳定高效执行,就涉及到Hive相关的参数调优,这个不管是实际工作中还是在求职面试中,都是一道必考题。在此之前,本人虽然也有很多小的总结,但是都零零散散不成体系,然后最近工作中在处理一些棘手的问题时,发现自己在此方面还是存在许多盲区。因此,在此做下总结,让自己深刻记忆,供大家批评指正。

1.文件优化

Hive是一个模式构建和分析工具,其底层的数据存储基于其他存储,通常来说是HDFS文件系统。而HDFS文件系统通常会由于各种业务数据本身的分布不均或者数据处理过程的方式不合理等原因,形成大文件(远大于HDFS系统块大小)或者过多的小文件(远小于HDFS系统块大小),这种情况在进行后续数据处理时通常会发生数据倾斜的现象,这种情况一般也是最多的情况,因此基于文件情况进行优化通常效果也最好。

1.1 小文件优化

Hive执行过程中实际通过mapreduce读取HDFS文件,一般情况一个文件会对应一个MapTask。过多的小文件(数KB或者数MB的文件),一方面会产生许多MapTask,造成大量资源浪费,另一方面很容易在map阶段或者reduce阶段产生倾斜。
此时可以考虑在读取前进行小文件合并读取操作:

输入时合并小文件

//每个Map最大输入大小(这个值决定了合并后文件的数量)
set mapred.max.split.size=256000000;
//一个节点上split的至少的大小(这个值决定了多个DataNode上的文件是否需要合并)
set mapred.min.split.size.per.node=100000000;
//一个交换机下split的至少的大小(这个值决定了多个交换机上的文件是否需要合并)
set mapred.min.split.size.per.rack=100000000;
//执行Map前进行小文件合并
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;

输出时合并小文件

//设置map端输出进行合并,默认为true
set hive.merge.mapfiles = true
//设置reduce端输出进行合并,默认为false
set hive.merge.mapredfiles = true
//设置合并文件的大小
set hive.merge.size.per.task = 256*1000*1000
//当输出文件的平均大小小于该值时,启动一个独立的MapReduce任务进行文件merge。
set hive.merge.smallfiles.avgsize=16000000

1.2 大文件优化

设置切片大小
当input的文件都很大,任务逻辑复杂,map执行非常慢的时候,可以考虑增加Map数,来使得每个map处理的数据量减少,从而提高任务的执行效率。
增加map的方法为:根据算法computeSliteSize(Math.max(minSize,Math.min(maxSize,blocksize)))=blocksize=128M,调整maxSize最大值。让maxSize最大值低于blocksize就可以增加map的个数。

具体用法:

//设置mapreduce输入的切片大小为100字节(默认为HDFS的块大小)
set mapreduce.input.fileinputformat.split.maxsize=100;

设置map个数(实测无效)
具体设置:

//设置mapreduce任务中mapTask的个数
set mapred.map.tasks=1000;

2.SQL优化

2.1分区过滤列裁剪

2.1.1 分区过滤

​ 可以在查询的过程中减少不必要的分区,减少读入的分区数目。

2.1.2 列裁剪

​ Hive在读数据的时候,可以只读取查询中所需要用到的列,而忽略其他列。

2.2 JOIN 优化

2.2.1 大表JOIN小表

hive中join时小表放左边,会使得小表被加载进内存中,直接在各个MR之间广播,从而在map阶段就完成join操作,即mapjoin。新版本Hive中默认是打开的(set hive.auto.convert.join=true;),因此现在大小表顺序不会影响性能,hive生成执行计划时会进行自动优化。

2.2.2 大表JOIN大表

空Key过滤

Join操作中,通常出现一表中的关联Key空值过多,导致关联后的少数reduce中分配了大量值,产生倾斜问题。

解决方法1: key为空的不参与关联,子查询过滤null

SELECT * FROM log a
JOIN bmw_users b ON a.user_id IS NOT NULL AND a.user_id=b.user_id
UNION ALL SELECT * FROM log a WHERE a.user_id IS NULL ;
//该方法会产生2个Job,扫描表2次,性能相对较差,不建议这样做

解决方法2: 关联key赋值打散

SELECT * FROM log a LEFT OUTER
JOIN bmw_users b ON
CASE WHEN a.user_id IS NULL THEN CONCAT('dp_hive', RAND()) ELSE a.user_id END = b.user_id;
//该方法会产生1个Job,扫描表1次,性能会好很多,而且空值数据被随机分配,分布均匀,很好解决了倾斜问题。

附:Hadoop通用关联的实现方法
关联通过二次排序实现的,关联的列为partition key,关联的列和表的tag组成排序的group key,根据partition key分配Reduce。同一Reduce内根据group key排序

2.2.3 MapJoin 优化

如果不指定MapJoin或者不符合MapJoin的条件,那么Hive解析器会将Join操作转换成Common Join,即:在Reduce阶段完成join。容易发生数据倾斜。可以用MapJoin把小表全部加载到内存在map端进行join,避免reducer处理

//设置自动选择,默认为true
set hive.auto.convert.join = true;
//大表小表的阀值设置(默认25M一下认为是小表)
set hive.mapjoin.smalltable.filesize=25000000;  

2.3 GROUP BY操作

默认情况下,Map阶段同一Key数据分发给一个reduce,当一个key数据过大时就倾斜了,进行GROUP BY操作时需要注意以下几点:

  1. Map端部分聚合

    事实上并不是所有的聚合操作都需要在reduce部分进行,很多聚合操作都可以先在Map端进行部分聚合,然后reduce端得出最终结果。

    (1)开启Map端聚合参数设置

    set hive.map.aggr=true

    (2)在Map端进行聚合操作的条目数目

    set hive.grouby.mapaggr.checkinterval=100000

    (3)有数据倾斜的时候进行负载均衡(默认是false)

    set hive.groupby.skewindata = true

  2. 有数据倾斜时进行负载均衡

    1. 此处需要设定hive.groupby.skewindata
      当选项设定为true时,生成的查询计划有两个MapReduce任务。在第一个MapReduce中,map的输出结果集合会随机分布到reduce中,每个reduce做部分聚合操作,并输出结果。这样处理的结果是,相同的Group By Key有可能分发到不同的reduce中,从而达到负载均衡的目的;第二个MapReduce任务再根据预处理的数据结果按照Group By Key分布到reduce中(这个过程可以保证相同的Group By Key分布到同一个reduce中),最后完成最终的聚合操作。

2.4 优化in/exists语句

hive1.2.1也支持in/exists操作,但还是推荐使用hive的一个高效替代方案:left semi join

//比如说:
select a.id, a.name from a where a.id in (select b.id from b);      
select a.id, a.name from a where 
		exists (select id from b where a.id = b.id);

//应该转换成:
select a.id, a.name from a left semi join b on a.id = b.id;

2.5 排序选择

  • cluster by: 对同一字段分桶并排序,不能和sort by连用;
  • distribute by + sort by: 分桶,保证同一字段值只存在一个结果文件当中,结合sort by 保证每个reduceTask结果有序;
  • sort by: 单机排序,单个reduce结果有序
  • order by:全局排序,缺陷是只能使用一个reduce

3.合理设置Map和Reduce个数

3.1 对Map和Reduce设置数量的出发点

出发点:使每个任务处理的数据量相对均衡,从而达到整体处理效率的一致,避免任务执行的长尾现象。

默认情况下,一个input目录中map任务的数量决定因素:input的文件总个数,input的文件大小,集群设置的文件块大
小文件过多存在的问题:过多小文件,造成申请容器资源过多,造成资源浪费,而且很容以出现倾斜问题。此时需要合并小文件,减少任务数。

文件正常但是文件是字段少行数多的长表:这种情况遇到复杂计算时效率也会比较低,此时需要设置任务数据摄取量,增加map任务数。

3.2 相关优化方法
3.2.1 复杂文件增加Map数

参考文件优化:大文件优化

3.2.2 小文件进行合并

参考文件优化:小文件优化

3.2.3 合理设置Reduce数

在设置reduce个数的时候也需要考虑这两个原则:
a.处理大数据量利用合适的reduce数;
b.使单个reduce任务处理数据量大小要合适;

//每个Reduce处理的数据量默认是256MB
	set hive.exec.reducers.bytes.per.reducer=256000000
//每个任务最大的reduce数,默认为1009
	set hive.exec.reducers.max=1009

4.推测执行

负载不均衡或者资源分布不均等原因,会造成同一个作业的多个任务之间运行速度不一致,有些任务的运行速度可能明显慢于其他任务(比如一个作业的某个任务进度只有50%,而其他所有任务已经运行完毕),则这些任务会拖慢作业的整体执行进度。
为了避免这种情况发生,Hadoop采用了推测执行(Speculative Execution)机制,它根据一定的法则推测出“拖后腿”的任务,并为这样的任务启动一个备份任务,让该任务与原始任务同时处理同一份数据,并最终选用最先成功运行完成任务的计算结果作为最终结果。

//设置MR推测执行:该参数属于MR框架的,设置hive的speculative是不起作用的
set mapred.map.tasks.speculative.execution=false;
set mapred.reduce.tasks.speculative.execution=false;

5.JVM重用

Hadoop的默认配置通常是使用派生JVM来执行map和Reduce任务的。这时JVM的启动过程可能会造成相当大的开销,尤其是执行的job包含有成百上千task任务的情况。JVM重用可以使得JVM实例在同一个job中重新使用N次。N的值可以在Hadoop的mapred-site.xml文件中进行配置。

//hive中设置MR任务JVM重用次数,通常在10-20之间,具体多少需要根据具体业务场景测试得出。
set mapred.job.reuse.jvm.num.tasks=10;

6.压缩

大数据场景下存储格式压缩格式尤为关键,可以提升计算速度,减少存储空间,降低网络io,磁盘io,所以要选择合适的压缩格式和存储格式,那么首先就了解这些东西。

参考该博客:https://blog.csdn.net/yu0_zhang0/article/details/79524842

7.存储格式

可以使用列裁剪,分区裁剪,orc,parquet等这些列式存储格式,因为列式存储的表,每一列的数据在物理上是存储在一起的,Hive查询时会只遍历需要列数据,大大减少处理的数据量。

8引擎的选择

hive目前支持多种引擎:MR/Spark/Tez
set hive.execution.engine = mr; --默认
set hive.execution.engine = tez; --较为成熟
set hive.execution.engine = spark; --在试验中,慎用

9.向量化查询

向量化查询执行通过一次性批量执行1024行而不是每次单行执行,从而提供扫描、聚合、筛选器和连接等操作的性能。在Hive 0.13中引入,此功能显着提高了查询执行时间。

//开启hive向量化执行(默认关闭)
set hive.vectorized.execution.enabled = true;
set hive.vectorized.execution.reduce.enabled = true;

10.设置CBO

Hive自0.14.0开始,加入了一项“Cost based Optimizer”来对HQL执行计划进行优化,这个功能通过“hive.cbo.enable”来开启。在Hive 1.1.0之后,这个feature是默认开启的,它可以自动优化HQL中多个JOIN的顺序,并选择合适的JOIN算法。Hive在提供最终执行前,优化每个查询的执行逻辑和物理执行计划。这些优化工作是交给底层来完成的。根据查询成本执行进一步的优化,从而产生潜在的不同决策:如何排序连接,执行哪种类型的连接,并行度等等。

//设置CBO开启(hive 1.1.0之后默认开启)
set hive.cbo.enable = true;
set hive.compute.query.using.stats = true;
set hive.stats.fetch.column.stats = true;
set hive.stats.fetch.partition.stats = true;

11.模式选择

11.1 Fetch抓取

只查询少量数据的简单查询,可以考虑Fetch抓取,即本地远程拉取数据而不走MR。

//Fetch抓取:more(默认是minimal)
set hive.fetch.task.conversion=more; 
11.2 本地模式

数据输入量少,申请MR资源的过程很可能比执行时间多的多,可以考虑使用本地模式。

//开启本地mr
set hive.exec.mode.local.auto=true; 
//设置local mr的最大输入文件个数(默认为4)
set hive.exec.mode.local.auto.input.files.max=10; 
//设置local mr的最大输入文件个数(默认为128M)
set hive.exec.mode.local.auto.inputbytes.max=50000000; 

12.执行计划

​ 略,后面专门出一个博客总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值