Hive优化(二)—具体优化操作

引语
  上一篇介绍了关于Hive优化的一些基本概念,这一篇主要讲hive性能优化的一些具体事项,这篇主要将对数据倾斜问题的优化,以及其他的方面的一些优化。
数据倾斜
什么是数据倾斜

  在Hadoop当项目中,数据倾斜可以说是损害Hadoop性能的罪魁祸首。在运行Hadoop的任务过程当中,我们可能因为业务的需要,避免不了需要按照某个字段分组,去重,进行多表连接等操作,在这些操作当中一旦有些使用不当,就会很容易造成数据倾斜。同样,当一个模型设计不合理时,job数量指定过多或者分区不恰当时也很容易影响Hadoop的性能。那么什么是数据倾斜?怎样避免或者处理数据倾斜问题呢?接下来就为大家介绍具体的关于解决数据倾斜问题的具体方案。

  数据倾斜就是key分布不均匀,导致分发到不同的reduce上,个别reduce任务特别重,导致其他reduce都完成,而这些个别的reduce迟迟不完成的情况 。

数据倾斜的原因

  key分布不均匀。

  map端数据倾斜,输入文件太多且大小不一 。

  reduce端数据倾斜,分区器问题。

  业务数据本身的特征。

数据倾斜的症状

  任务长时间维持在99%(或100%),查看任务监控页面,发现只有少量(1个或几个)reduce子任务未完成。

  查看子任务,可以看到本地读写数据量积累非常大,通常超过10GB可以认定发生了数据倾斜。

  平均记录数超过50w且最大记录数超过平均记录数的4配

  最长时长超过平均时长4分钟,且最大时长超过平均时长的2倍

  一般来说集群的整体性能,是由执行任务时间最长的那个节点决定的。所以,有效地解决数据倾斜问题,就能有效地提高整个集群的性能。接下来我们来看一下具体的解决方法吧。

数据倾斜—大大表关联

  有时join超时是因为某些key对应的数据太多,而相同key对应的数据都会发送到相同的reducer上,从而导致内存不够。此时我们应该仔细分析这些异常的key,很多情况下,这些key对应的数据是异常数据,我们需要在SQL语句中进行过滤。同时当有筛选条件时,应该先按照条件进行过滤,然后在进行join,这样可以减少数据量。

数据倾斜—大小表关联

  原因:Hive在进行join时是以左边的表为准的,在join左边的表的数据会首先读入内存,如果左边的表key比较集中,而表的数据量又比较大,这样就会导致加入内存的数据过大,最终就会出现严重的数据倾斜。相反如果左边的表,key相对分散,那么读入内存的数据会比较小,join任务执行会比较快,就不会出现数据倾斜的现象。

  解决思路:
    将key相对分散,并且将数据量小的表放在join的左边,这样可以有效减少内存溢出错误发生的几率。

    使用map join让小的维度表先进内存。使用map join,会将其中做连接的小表(全量数据)分发到所有 MapTask 端进行 Join,从 而避免reduceTask,前提要求是内存足以装下该全量数据。

数据倾斜—聚合时存在大量特殊值

  原因:做count distinct时,该字段存在大量值为NULL或空的记录。

  思路:count distinct时,将值为空的情况单独处理,如果是计算count distinct,可以不用处理,直接过滤,在最后结果中加1。
  如果还有其他计算,需要进行group by,可以先将值为空的记录单独处理,再和其他计算结果进行union。

其他hive优化
Hive的并行执行

  同步执行hive的多个阶段,hive在执行过程,将一个查询转化成一个或者多个阶段。某个特定的job可能包含众多的阶段,而这些阶段可能并非完全相互依赖的,也就是说可以并行执行的,这样可能使得整个job的执行时间缩短。hive执行开启:set hive.exec.parallel=true

设置本地运行

  Hive 在集群上查询时,默认是在集群上N台机器上运行, 需要多个机器进行协调运行,这个方式很好地解决了大数据量的查询问题。但是当 Hive 查询处理的数据量比较小时,其实没有必要启动分布式模式去执行,因为以分布式方式执行就涉及到跨网络传输、多节点协调 等,并且消耗资源。这个时间可以只使用本地模式来执行 mapreduce job,只在一台机器上执行,速度会很快。启动本地模式可以通过配置参数来达到这个目的:

参数名默认值作用
set hive.exec.mode.local.autofalse是否让hive在本地运行
hive.exec.mode.local.auto.input.files.max4是否启用本地模式的task的最大个数
hive.exec.mode.local.auto.inputbytes.max128M是否启动本地模式最大文件输入大小

  参数说明:

    set hive.exec.mode.local.auto=true 开启本地mr,只是打开 hive 自动判断是否启动本地模式的开关,也就是打开这个参数并不能保证启动本地模式,是否启动还要取决于 map 任务数量。

    set hive.exec.mode.local.auto.input.files.max 设置local mr的最大输入文件个数,当输入文件个数小于这个值时采用local mr的方式,默认为4。

    hive.exec.mode.local.auto.inputbytes.max 当指定大小时,才会启动本地模式,不指定则默认不启动。 如果当输入文件大小小于此阈值时可以自动在本地模式运行,默认是 128兆。

严格模式
  Hive中提供有严格模式,为了防止一些查询。出现不好的影响。例如笛卡儿积,在严格模式下是不能运行的。配置如下:
<property>
	<name>hive.mapred.mode</name>
	<value>strict</value>
</property>

  说明
    默认值为:非严格模式 nonstrict
    开启严格模式: strict
  开启了严格模式,会对查询语句进行一些限制:
  1 对于分区表: 必须存在where语句对分区表中分区字段进行条件过滤,否则,不允许执行该查询。
  2 对于使用order by的语句必须使用limit 进行限定,由于order by 之后所有的数据都会被分到一个reduce中那这样reduce操作的数据量太多了,可能时间过长卡死。所以为了防止reduce时间过长,在order by的时候必须给定 limit 减少redue处理的数据量。
  3 限制了笛卡儿积的查询,主要在多表join中会出现。笛卡儿积的出现会造成性能极大的消耗。

推测执行

  在Hadoop中,作业完成时间取决于最慢的任务完成时间。一个作业由若干个Map任务和Reduce任务构成。因集群中的资源分配不均等、硬件老化、软件Bug等,会导致某个任务运行的时间快或者某个任务运行的时间慢,或者某个任务在运行的时候直接卡死了。;为了防止某些任务,在运行过程中,拖慢了整个MR任务的进度。在运行慢的任务节点上开启相同的任务,如果时间比原来的任务运行的快则直接输出推测运行的任务 。

  典型案例:系统中有99%的Map任务都完成了,只有少数几个Map老是进度很慢,完不成,怎么办?

  推测执行机制

    发现拖后腿的任务,比如某个任务运行速度远慢于任务平均速度。为拖后腿任务启动一个备份任务,同时运行。谁先运行完,则采用谁的结果。

  执行推测任务的前提条件

    (1)每个task只能有一个备份任务;

    (2)当前job已完成的task必须不小于0.05(5%)

    (3)开启推测执行参数设置。Hadoop2.7.2 mapred-site.xml文件中默认是打开的。

<property>
  <name>mapreduce.map.speculative</name>
  <value>true</value>
  <description>If true, then multiple instances of some map tasks may be executed in parallel.
  </description>
</property>
<property>
  <name>mapreduce.reduce.speculative</name>
  <value>true</value>
  <description>
  	If true, then multiple instances of some reduce tasks may be executed in parallel.
  </description>
</property>

  mapred.map.tasks.speculative.execution boolean true 如果任务运行变慢,该属性决定了是否要启动一个map任务的另外一个实力

  mapred.reduce.tasks.speculative.execution boolean true 如果任务运行变慢,该属性决定这是否需要启动一个reduce任务

执行计划
  Hive中提供的可以查看Hql语句的执行计划,在执行计划中会生成抽象语法树,在语法树中会显示HQL语句之间的依赖关系以及执行过程。通过这些执行的过程和依赖可以对HQL语句进行优化
JVM重用

  在hive执行计算任务的时候,会把的执行计划上传到yarn集群中进行提交,运行MR任务。每次进行任务的运行的时候都会开启一个JVM进程运行的MR任务。如果提交任务频繁过多就会造成JVM频繁的开启和关闭,正常情况下,MapReduce启动的JVM在完成一个task之后就退出了,但是如果任务花费时间很短,又要多次启动JVM的情况下,JVM的启动时间就会变成一个比较大的overhead。
  在这种情况下,可以使用jvm重用的参数:set Mapred.Job.reuse.jvm.num.tasks = 5; 。其作用是让一个jvm运行多次任务之后再退出,节约JVM的启动时间。

小文件的合并

  大量的小文件导致文件数目过多,例如当一个文件是130MB的时候,Hadoop会将这个文件分成2个默认块,一个是128MB剩余的分一个2MB另外分一个,这样就会给HDFS带来压力,对hive处理的效率影响比较大,对于小文件问题有两种处理方法。

  设置hive参数,将额外启动一个MR Job打包小文件

hive.merge.mapfiles=true(默认值为真) 是否合并Map输出文件
hive.merge.mapredfiles=false(默认值为假)是否合并Reduce 端输出文件
hive.merge.size.per.task=256*1000*1000(默认值为 256000000)合并文件的大小

  使用Combinefileinputformat,将多个小文件打包作为一个整体的inputsplit,减少map任务数。前面三个参数确定合并文件块的大小,大于文件块大小128m的,按照128m来分隔,小于128m,大于100m的,按照100m来分隔,把那些小于100m的(包括小文件和分隔大文件剩下的)进行合并

set mapred.max.split.size=100000000;
set mapred.min.split.size.per.node=100000000
set  Mapred.min.split.size.per.rack=100000000
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat
合理利用文件存储格式

  创建表时,尽量使用 orc、parquet 这些列式存储格式,因为列式存储的表,每一列的数据在物理上是存储在一起的,Hive查询时会只遍历需要列数据,大大减少处理的数据量。同时由于parquet文件是以二进制存储的,因此可以减少文件的序列化和法序列化的操作,从而节省时间。

对文件进行适当的压缩

  Hive 最终是转为 MapReduce 程序来执行的,而MapReduce 的性能瓶颈在于网络 IO 和 磁盘 IO,要解决性能瓶颈,最主要的是减少数据量,对数据进行压缩是个好的方式。压缩 虽然是减少了数据量,但是压缩过程要消耗CPU的,但是在Hadoop中, 往往性能瓶颈不在于CPU,CPU压力并不大,所以压缩充分利用了比较空闲的 CPU。

减少Job的数量

  对于一个job能够完成的任务,尽量不要使用两个job来完成,从而减少job初始化所需要的时间。

程序角度

  熟练使用SQL提高查询,写出高效率的查询语句。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值