网站首页 > 技术文章 正文
我们都知道Hive是基于Hadoop的一个数据仓库工具,可以对数据进行提取、转化、加载,处理海量的数据。那么在数据处理的过程中都会遇见哪些问题呢,数据量大不是问题,但是数据倾斜却是我们在企业中最常见的问题。而且job数量较多也会影响任务执行的效率,下面就让我们一起来看看在各种情况下Hive常见的优化方式吧。
一、Fetch抓取?
Fetch抓取是指,Hive中对某些情况的查询可以不必使用MapReduce计算。比如:select * from student,在这种情况下,Hive可以简单地读取student对应的存储目录下的文件,然后输出查询结果到控制台。
在hive-default.xml.template文件中有个配置项hive.fetch.task.conversion默认是more(老版本hive默认是minimal),该属性设置为more以后,在全局查找、字段查找、limit查找等都不走MapReduce程序,但若把hive.fetch.task.conversion设置成none,然后执行查询语句,那么就都会执行MapReduce程序。
<property>
<name>hive.fetch.task.conversion</name>
<value>more</value>
</property>
二、对表的优化?
关于小表和大表之间的join
将key相对分散,并且数据量小的表放在join的左边,这样可以有效减少内存溢出错误发生的几率;再进一步,可以使用Map join让小的维度表(1000条以下的记录条数)进入内存。在Map端完成Reduce。?
但是实际测试发现:新版的Hive已经对小表join大表和大表join小表进行了优化。小表放在左边和右边已经没有明显区别。
关于大表和大表之间的join
(1)空key过滤:有时join超时是因为某些key对应的数据太多,而相同key对应的数据都会发送到相同的Reducer上,从而导致内存不够。此时我们应该仔细分析这些异常的key,很多情况下,这些key对应的数据是异常数据,我们可以在SQL语句中进行过滤。例如key对应的字段为空,我们就可以过滤掉这些不合格的数据。
(2)空key转换:有时虽然某个key为空对应的数据很多,但是相应的数据不是异常数据,必须要包含在join的结果中,此时我们可以为表中key为空的字段赋一个随机的值,使得数据随机均匀地分布到不同的Reducer上,这样也可以有效的避免数据倾斜。
(3)group by:默认情况下,Map阶段同一key数据分发给一个Reduce,当一个key数据过大时就倾斜了。但是并不是所有的聚合操作都需要在Reduce端完成,很多聚合操作都可以先在Map端进行部分聚合,最后在Reduce端得出最终结果。
<1> 是否在Map端进行聚合,默认为true。
set hive.map.aggr = true
<2>在Map端进行聚合操作的条目数目。
set hive.groupby.mapaggr.checkinterval = 100000
<3>有数据倾斜的时候进行负载均衡,默认是false。
set hive.groupby.skewindata = true
(4)尽量避免笛卡尔积,join的时候不加on条件或者无效的on条件,Hive只能使用1个Reducer来完成笛卡尔积。
(5)count(distinct) 去重统计:数据量小的时候无所谓,数据量大的情况下,由于count distinct操作需要用一个Reduce Task来完成,这一个Reduce需要处理的数据量太大,就会导致整个job很难完成,一般count distinct使用先group by再count的方式替换。?
三、合理设置Map和Reduce的数量?
通常情况下,作业会通过input的目录产生一个或者多个Map任务。主要的决定因素有:input的文件总个数、input的文件大小、集群设置的文件块大小。
问1:是不是Map数越多越好?
答案是否定的。如果一个任务有很多小文件(远远小于块大小128m),则每个小文件也会被当做一个块,用一个Map任务来完成,而一个Map任务启动和初始化的时间远远大于逻辑处理的时间,就会造成很大的资源浪费。而且,同时可执行的Map数是受限的。
问2:是不是保证每个Map处理接近128m的文件块,就高枕无忧了?
答案也是不一定。比如有一个127m的文件,正常会用一个Map去完成,但这个文件只有一个或者两个小字段,却有几千万的记录,如果Map处理的逻辑比较复杂,用一个Map任务去做,肯定也比较耗时。
针对上面的问题,我们需要采取两种方式来解决:即减少Map数和增加Map数。
复杂文件增加Map数量
当input的文件都很大,任务逻辑复杂,Map执行非常慢的时候,可以考虑增加Map数,来使得每个Map处理的数据量减少,从而提高任务的执行效率。增加Map的方法为:根据以下公式:调整maxSize最大值。让maxSize最大值低于blocksize就可以增加Map的个数。
computeSliteSize(Math.max(minSize,Math.min(maxSize,blocksize))) = blocksize=128M
设置最大切片值为100个字节。
set mapreduce.input.fileinputformat.split.maxsize = 100
小文件进行合并
(1)在Map执行前合并小文件,减少Map数:CombineHiveInputFormat具有对小文件进行合并的功能(系统默认的格式)。HiveInputFormat没有对小文件合并功能。
set hive.input.format = org.apache.hadoop.hive.ql.io.CombineHiveInputFormat
(2) 在Map-Reduce的任务结束时合并小文件的设置:在Map-Only任务结束时合并小文件,默认true。
set hive.merge.mapfiles = true
(3) 在Map-Reduce任务结束时合并小文件,默认false。
set hive.merge.mapredfiles = true
(4) 合并文件的大小,默认256M。
set hive.merge.size.per.task = 256000000
(5) 当输出文件的平均大小小于该值时,启动独立的MR进行文件merge。
合理设置Reduce数量
(1) 每个Reduce处理的数据量默认是256M。
set hive.exec.reducers.bytes.per.reducer = 256000000
(2)每个任务最大的Reduce数,默认为1009。
set hive.exec.reducers.max = 1009
(3)计算Reducer数的公式。
N = min(参数2,总输入数据量/参数1)
(4)在Hadoop的mapred-default.xml文件中修改设置job的Reduce个数。
set mapreduce.job.reduces = 15
注意:Reduce个数并不是越多越好,过多的启动和初始化Reduce也会消耗时间和资源。另外,有多少个Reduce,就会有多少个输出文件,如果生成了很多个小文件,那么如果这些小文件作为下一个任务的输入,则也会出现小文件过多的问题,在设置Reduce个数的时候也需要考虑两个原则:处理大数据量利用合适的Reduce数,使单个Reduce任务处理数据量大小要合适。
四、并行执行
Hive会将一个查询转化成一个或者多个阶段。这样的阶段可以是MapReduce阶段、抽样阶段、合并阶段、limit阶段。或者Hive执行过程中可能需要的其他阶段。默认情况下,Hive一次只会执行一个阶段。不过某个特定的job可能包含众多的阶段,而这些阶段可能并非完全互相依赖的,也就是说有些阶段是可以并行执行的,这样可能使得整个job的执行时间缩短。不过,如果更多的阶段可以并行执行,那么job可能就越快完成。
通过设置参数hive.exec.parallel值为true,就可以开启并发执行。不过,在共享集群中,需要注意下,如果job中并行阶段增多,那么集群利用率就会增加。当然,得是在系统资源比较空闲的时候才有优势,否则,没资源,并行也起不来。
set hive.exec.parallel = true //打开任务并行执行
set hive.exec.parallel.thread.number = 16 //同一个sql允许最大并行度,默认为8
五、严格模式
Hive可以通过一些参数设置防止一些危险的操作。
1、将hive.strict.checks.no.partition.filter设置为true时,对于分区表,除非where语句中含有分区字段过滤条件来限制范围,否则不允许执行。换句话说,就是用户不允许扫描所有分区。进行这个限制的原因是,通常分区表都拥有非常大的数据集,而且数据增加迅速。没有进行分区限制的查询可能会消耗令人不可接受的巨大资源来处理这个表。
set hive.strict.checks.no.partition.filter = true
2、将hive.strict.checks.orderby.no.limit设置为true时,对于使用了order by语句的查询,要求必须使用limit语句。因为order by为了执行排序过程会将所有的结果数据分发到同一个Reducer中进行处理,强制要求用户增加这个limit语句可以防止Reducer额外执行很长一段时间。
set hive.strict.checks.orderby.no.limit = true
3、将hive.strict.checks.cartesian.product设置为true时,会限制笛卡尔积的查询。对关系型数据库非常了解的用户可能期望在执行join查询的时候不使用on语句而是使用where语句,这样关系数据库的执行优化器就可以高效地将where语句转化成那个on语句。不幸的是,Hive并不会执行这种优化,因此,如果表足够大,那么这个查询就会出现不可控的情况。
set hive.strict.checks.cartesian.product = true
六、压缩
Hive最终是转为MapReduce程序来执行的,而MapReduce的性能瓶颈在于网络IO和磁盘IO,要解决性能瓶颈,最主要的是减少数据量,对数据进行压缩是个好的方式。压缩虽然是减少了数据量,但是压缩过程要消耗CPU的,但是在Hadoop中,往往性能瓶颈不在于CPU,CPU压力并不大,所以压缩充分利用了比较空闲的CPU。
创建表时,尽量使用orc、parquet这些列式存储格式,因为列式存储的表,每一列的数据在物理上是存储在一起的,Hive查询时会只遍历需要列数据,大大减少处理的数据量。job 输出文件按照 block 以 GZip 的方式进行压缩。
set mapreduce.output.fileoutputformat.compress = true //默认值是false
set mapreduce.output.fileoutputformat.compress.type = BLOCK //默认值是Record
set mapreduce.output.fileoutputformat.compress.codec = org.apache.hadoop.io.compress.GzipCodec //默认值是org.apache.hadoop.io.compress.DefaultCodec
Map 输出结果也以 Gzip 进行压缩。
set mapred.map.output.compress = true
set mapreduce.map.output.compress.codec = org.apache.hadoop.io.compress.GzipCodec
对 Hive 输出结果和中间都进行压缩。
set hive.exec.compress.output = true //默认值是false,不压缩
set hive.exec.compress.intermediate = true //默认值是false,为true时MR设置的压缩才启用
七、本地模式?
大多数的Hadoop job是需要Hadoop提供的完整的可扩展性来处理大数据集的。不过,有时Hive的输入数据量是非常小的。在这种情况下,为查询触发执行任务消耗的时间可能会比实际job的执行时间要多很多。对于大多数这种情况,Hive可以通过本地模式在单台机器上处理所有的任务。对于小数据集,执行时间可以明显被缩短。用户可以通过设置hive.exec.mode.local.auto的值为true,来让Hive在适当的时候自动启动这个优化。
set hive.exec.mode.local.auto = true //开启本地MR
设置local MR的最大输入数据量,当输入数据量小于这个值时采用local MR的方式,默认为134217728,即128M。
set hive.exec.mode.local.auto.inputbytes.max = 134217728
设置local MR的最大输入文件个数,当输入文件个数小于这个值时采用local MR的方式,默认为4。
set hive.exec.mode.local.auto.input.files.max = 4
八、JVM重用
JVM重用可以使得JVM实例在同一个job中重新使用N次,N的值可以在Hadoop的mapred-site.xml文件中进行配置。通常在10-20之间。
<property>
<name>mapreduce.job.jvm.numtasks</name>
<value>10</value>
<description>How many tasks to run per jvm,if set to -1 ,there is no limit</description>
</property>
九、总结
本文讲述了Hive的常见的一些调优参数的设置以及调优思路,具体解决Hive执行过程中的某一个job效率低下的问题,还需要根据具体的情况而选择调优的方式,在这里希望能提供给大家一些解决问题的思路。
猜你喜欢
- 2024-10-12 大数据分析工具——hive入门 hive数据分析的一般流程是什么
- 2024-10-12 019Hive基本使用03 019Hive基本使用03 #liaoit
- 2024-10-12 手把手教你搭建Hive环境 搭建hive集群
- 2024-10-12 0474-如何使用SQL Developer访问Hive
- 2024-10-12 大数据之-HIVE入门(十四) php hive大数据处理
- 2024-10-12 Hive 迁移参考方案及测试(下) hive表迁移
- 2024-10-12 0263-Hive2.2.0如何与CDH集群中的Spark1.6集成
- 2024-10-12 如何在HUE上通过oozie调用Hive SQL工作流
- 2024-10-12 HiveSQL:如何从给定的日期中减去指定数量的天数?
- 2024-10-12 0671-6.2.0-如何将CDH5.12的Hive元数据迁移到CDH6.2
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- oraclesql优化 (66)
- 类的加载机制 (75)
- feignclient (62)
- 一致性hash算法 (71)
- dockfile (66)
- 锁机制 (57)
- javaresponse (60)
- 查看hive版本 (59)
- phpworkerman (57)
- spark算子 (58)
- vue双向绑定的原理 (68)
- springbootget请求 (58)
- docker网络三种模式 (67)
- spring控制反转 (71)
- data:image/jpeg (69)
- base64 (69)
- java分页 (64)
- kibanadocker (60)
- qabstracttablemodel (62)
- java生成pdf文件 (69)
- deletelater (62)
- com.aspose.words (58)
- android.mk (62)
- qopengl (73)
- epoch_millis (61)
本文暂时没有评论,来添加一个吧(●'◡'●)