当HiveQL跑不出来时,基本上是数据倾斜了,比如出现count(distinct),groupby,join等情况,理解 MR 底层原理,同时结合实际的业务,数据的类型,分布,质量状况等来实际的考虑如何进行系统性的优化。

Hive on MR 调优主要从三个层面进行,分别是基于MapReduce优化、Hive架构层优化和HiveQL层优化。

MapReduce调优

  如果能够根据情况对shuffle过程进行调优,对于提供MapReduce性能很有帮助。一个通用的原则是给shuffle过程分配尽可能大的内存,当然你需要确保map和reduce有足够的内存来运行业务逻辑。因此在实现Mapper和Reducer时,应该尽量减少内存的使用,例如避免在Map中不断地叠加。
运行map和reduce任务的JVM,内存通过mapred.child.java.opts属性来设置,尽可能设大内存。容器的内存大小通过mapreduce.map.memory.mb和mapreduce.reduce.memory.mb来设置,默认都是1024M。

1 map调优

  在map阶段主要包括:数据的读取、map处理以及写出操作(排序和合并/sort&merge),其中可以针对spill文件输出数量、Combiner的merge过程和数据压缩进行优化,避免写入多个spill文件可能达到最好的性能,一个spill文件是最好的。通过估计map的输出大小,设置合理的mapreduce.task.io.sort.*属性,使得spill文件数量最小。例如尽可能调大mapreduce.task.io.sort.mb。其次增加combine阶段以及对输出进行压缩设置进行mapper调优。

(1) 合理设置map数

在执行map函数之前会先将HDFS上文件进行分片,得到的分片做为map函数的输入,所以map数量取决于map的输入分片(inputsplit),一个输入分片对应于一个map task,输入分片由三个参数决定:

  1. 参数名 默认值 备注
  2. dfs.block.size 128M HDFS上数据块的大小
  3. mapreduce.min.split.size 0 最小分片数
  4. mapreduce.max.split.size 256M 最大分片数

公式:分片大小=max(mapreduce.min.split.size,min(dfs.block.size, mapreduce.max.split.size)),默认情况下分片大小和dfs.block.size是一致的,即一个HDFS数据块对应一个输入分片,对应一个map task。这时候一个map task中只处理一台机器上的一个数据块,不需要将数据跨网络传输,提高了数据处理速度。

(2)spill文件输出数量

  1. --用于mapper输出排序的内存大小,调大的话,会减少磁盘spill的次数,此时如果内存足够的话,一般都会显著提升性能
  2. mapreduce.task.io.sort.mbdefault100
  3. --开始spill的缓冲池阀值,默认0.80spill一般会在Buffer空间大小的80%开始进行spill
  4. mapreduce.map.sort.spill.percentdefault0.80

(3)combine(排序和合并/sort&merge)

  1. --运行combiner的最低文件数,与reduce共用;调大来减少merge的次数,从而减少磁盘的操作;
  2. mapreduce.task.io.sort.factordefault10
  3. --spill的文件数默认情况下由三个的时候就要进行combine操作,最终减少磁盘数据;
  4. min.num.spill.for.combine 默认是3

(4)压缩设置

  1. --设置为true进行压缩,数据会被压缩写入磁盘,,压缩一般可以10倍的减少IO操作
  2. mapreduce.map.output.compressdefaultfalse
    --压缩算法,推荐使用SnappyCodec
    mapreduce.map.output.compress.codecdefaultorg.apache.hadoop.io.compress.DefaultCodec

2 reduce调优

  在reduce端,如果能够让所有数据都保存在内存中,可以达到最佳的性能。通常情况下,内存都保留给reduce函数,但是如果reduce函数对内存需求不是很高,将mapreduce.reduce.merge.inmem.threshold(触发合并的map输出文件数)设为0,mapreduce.reduce.input.buffer.percent(用于保存map输出文件的堆内存比例)设为1.0,可以达到很好的性能提升。在2008年的TB级别数据排序性能测试中,Hadoop就是通过将reduce的中间数据都保存在内存中胜利的。

(1)对mapper端输出数据的获取

  1. --mr程序reducer copy数据的线程数。当map很多并且完成的比较快的job的情况下调大,有利于reduce更快的获取属于自己部分的数据
  2. mapreduce.reduce.shuffle.parallelcopies 默认5

(2)数据合并(sort&merge)

  1. --reduce复制map数据的时候指定的内存堆大小百分比,适当的增加该值可以减少map数据的磁盘溢出,能够提高系统能。
  2. mapreduce.reduce.shuffle.input.buffer.percent 默认0.70
  3. --reduce进行shuffle的时候,用于启动合并输出和磁盘溢写的过程的阀值。
    --如果允许,适当增大其比例能够减少磁盘溢写次数,提高系统性能。同mapreduce.reduce.shuffle.input.buffer.percent一起使用。
  4. mapreduce.reduce.shuffle.merge.percent 默认0.66

(3)reduce处理以及写出操作

  1. --reduce函数开始运行时,内存中的map输出所占的堆内存比例不得高于这个值,默认情况内存都用于reduce函数,也就是map输出都写入到磁盘
  2. set mapreduce.reduce.input.buffer.percent 默认0.0;
  3. --开始spillmap输出文件数阈值,小于等于0表示没有阈值,此时只由缓冲池比例来控制
  4. set mapreduce.reduce.merge.inmem.threshold 默认1000;
    --服务于reduce提取结果的线程数量
    mapreduce.shuffle.max.threads 默认0
    --修改reducer的个数,可以通过job.setNumReduceTasks方法来进行更改。
    mapreduce.job.reduces 默认为1;

(4)合理设置reduce数

reduce数决定参数

  1. 参数名 默认值 备注
  2. hive.exec.reducers.bytes.per.reducer 1G 一个reduce数据量的大小
  3. hive.exec.reducers.max 999 hive 最大的个数
  4. mapred.reduce.tasks -1 reduce task 的个数,-1 是根据hive.exec.reducers.bytes.per.reducer 自动调整

所以可以用set mapred.reduce.tasks手动调整reduce task个数。

Hive架构层优化

1 不执行mapreduce

hive从HDFS读取数据,有两种方式:启用mapreduce读取、直接抓取。

set hive.fetch.task.conversion=more

hive.fetch.task.conversion参数设置成more,可以在 select、where 、limit 时启用直接抓取方式,能明显提升查询速度。

2 本地执行mapreduce

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

3 JVM重用

因为hive语句最终要转换为一系列的mapreduce job的,而每一个mapreduce job是由一系列的map task和Reduce task组成的,默认情况下,mapreduce中一个map task或者一个Reduce task就会启动一个JVM进程,一个task执行完毕后,JVM进程就退出。这样如果任务花费时间很短,又要多次启动JVM的情况下,JVM的启动时间会变成一个比较大的消耗,这个时候,就可以通过重用JVM来解决。这个设置就是制定一个jvm进程在运行多次任务之后再退出,这样一来,节约了很多的 JVM的启动时间。

  1. --JVM重用特别是对于小文件场景或者task特别多的场景
  2. set mapred.job.reuse.jvm.num.tasks=10;
  3.  
  4. --启动JVM虚拟机时,传递给虚拟机的启动参数,表示这个 Java 程序可以使用的最大堆内存数,一旦超过这个大小,JVM 就会抛出 Out of Memory 异常,并终止进程。
  5. --设置的是 Container 的内存上限,这个参数由 NodeManager 读取并进行控制,当 Container 的内存大小超过了这个参数值,NodeManager 会负责 kill Container
  6. --mapreduce.map.java.opts一定要小于mapreduce.map.memory.mb
  7. mapreduce.map.java.opts 默认 -Xmx200m
  8. mapreduce.map.memory.mb
  9. --同上
  10. mapreduce.reduce.java.opts
  11. mapreduce.map.java.opts
  12.  
  13. --是否启动map阶段的推测执行,其实一般情况设置为false比较好。可通过方法job.setMapSpeculativeExecution来设置。
  14. mapreduce.map.speculative 默认为true;
  15. --是否需要启动reduce阶段的推测执行,其实一般情况设置为fase比较好。可通过方法job.setReduceSpeculativeExecution来设置。
  16. mapreduce.reduce.speculative 默认为true;

4 并行化

一个hive sql语句可能会转为多个mapreduce job,每一个job就是一个stage,这些 job 顺序执行,这个在hue的运行日志中也可以看到。但是有时候这些任务之间并不是是相互依赖的,如果集群资源允许的话,可以让多个并不相互依赖stage并发执行,这样就节约了时间,提高了执行速度,但是如果集群资源匮乏时,启用并行化反倒是会导致各个job相互抢占资源而导致整体执行性能的下降。

  1. --开启任务并行执行
  2. set hive.exec.parallel=true;
  3. --同一个sql允许并行任务的最大线程数
  4. set hive.exec.parallel.thread.number 默认为8;

HiveQL调优

1 利用分区表优化

分区表是在某一个或者某几个维度上对数据进行分类存储,一个分区对应于一个目录。在这中的存储方式,当查询时,如果筛选条件里有分区字段,那么hive只需要遍历对应分区目录下的文件即可,不用全局遍历数据,使得处理的数据量大大减少,提高查询效率。
当一个hive表的查询大多数情况下,会根据某一个字段进行筛选时,那么非常适合创建为分区表。

2 利用桶表优化

就是指定桶的个数后,存储数据时,根据某一个字段进行哈希后,确定存储再哪个桶里,这样做的目的和分区表类似,也是使得筛选时不用全局遍历所有的数据,只需要遍历所在桶就可以了。

  1. hive.optimize.bucketmapJOIN=true;
  2. hive.input.format=org.apache.hadoop.hive.ql.io.bucketizedhiveInputFormat;
  3. hive.optimize.bucketmapjoin=true;
  4. hive.optimize.bucketmapjoin.sortedmerge=true;

3 对于整个sql的优化

(1)where 条件优化
where只在map端阶段执行,不会在reduce阶段执行,尽早地过滤数据,减少每个阶段的数据量,对于分区表要加分区,同时只选择需要使用到的字段。
(2)join优化

  1. 优先过滤后再join,最大限度地减少参与join的数据量。
  2. 小表join大表原则
  3. 应该遵守小表join大表原则,原因是join操作的reduce阶段,位于join左边的表内容会被加载进内存,将条目少的表放在左边,可以有效减少发生内存溢出的几率。join中执行顺序是从做到右生成job,应该保证连续查询中的表的大小从左到右是依次增加的。
  4. join on条件相同的放入一个job
  5. hive中,当多个表进行join时,如果join on的条件相同,那么他们会合并为一个mapreduce job,所以利用这个特性,可以将相同的join on的放入一个job来节省执行时间。
  6.   select pt.page_id,count(t.url) PV
  7.   from rpt_page_type pt
  8.   join (select url_page_id,url from trackinfo where ds='2016-10-11' ) t on pt.page_id=t.url_page_id
  9.   join (select page_id from rpt_page_kpi_new where ds='2016-10-11' ) r on t.url_page_id=r.page_id group by pt.page_id;
  10. Common/shuffle/Reduce JOIN
  11. 发生在reduce 阶段, 适用于大表 连接 大表(默认的方式)
  12. Map JOIN
  13. 连接发生在map阶段 ,适用于小表 连接 大表,大表的数据从文件中读取,小表的数据存放在内存中(hive中已经自动进行了优化,自动判断小表,然后进行缓存)
  14.   set hive.auto.convert.join=true;
  15. SMB JOIN,Sort -Merge -Bucket Join 对大表连接大表的优化,用桶表的概念来进行优化。在一个桶内发送生笛卡尔积连接(需要是两个桶表进行join
  16.   set hive.auto.convert.sortmerge.join=true;
      set hive.optimize.bucketmapjoin = true;
  17.   set hive.optimize.bucketmapjoin.sortedmerge = true;
  18.   set hive.auto.convert.sortmerge.join.noconditionaltask=true;

(3) Group By数据倾斜优化
  Group By很容易导致数据倾斜问题,因为实际业务中,通常是数据集中在某些点上,这也符合常见的2/8原则,这样会造成对数据分组后,某一些分组上数据量非常大,而其他的分组上数据量很小,而在mapreduce程序中,同一个分组的数据会分配到同一个reduce操作上去,导致某一些reduce压力很大,其他的reduce压力很小,这就是数据倾斜,整个job 执行时间取决于那个执行最慢的那个reduce。
解决这个问题的方法是配置一个参数:set hive.groupby.skewindata=true。 当选项设定为true,生成的查询计划会有两个MR job。第一个MR job 中,map的输出结果会随机分布到Reduce中,每个Reduce做部分聚合操作,并输出结果,这样处理的结果是相同的Group By Key有可能被分发到不同的Reduce中,从而达到负载均衡的目的;第二个MR job再根据预处理的数据结果按照Group By Key分布到Reduce中(这个过程可以保证相同的GroupBy Key被分布到同一个Reduce中),最后完成最终的聚合操作。
(4) Order By 优化
  因为order by只能是在一个reduce进程中进行的,所以如果对一个大数据集进行order by,会导致一个reduce进程中处理的数据相当大,造成查询执行超级缓慢。
(5)mapjoin
  mapjoin是将join双方比较小的表直接分发到各个map进程的内存中,在map进程中进行join操作,这样就省掉了reduce步骤,提高了速度。
但慎重使用mapjoin,一般行数小于2000行,大小小于1M(扩容后可以适当放大)的表才能使用,小表要注意放在join的左边。否则会引起磁盘和内存的大量消耗。
(6) 桶表mapjoin
  当两个分桶表join时,如果join on的是分桶字段,小表的分桶数时大表的倍数时,可以启用map join来提高效率。启用桶表mapjoin要启用hive.optimize.bucketmapjoin参数。
(7) 消灭子查询内的 group by 、 COUNT(DISTINCT),MAX,MIN。 可以减少job的数量。
(8) 不要使用count (distinct cloumn) ,改使用子查询。
(9) 如果union all的部分个数大于2,或者每个union部分数据量大,应该拆成多个insert into 语句,这样会提升执行的速度。尽量不要使用union (union 去掉重复的记录)而是使用 union all 然后在用group by 去重。
(10) 中间临时表使用orc、parquet等列式存储格式。
(11) Join字段显示类型转换。
(12) 单个SQL所起的JOB个数尽量控制在5个以下。

Hive on MR调优的更多相关文章

  1. 大数据学习day28-----hive03------1. null值处理,子串,拼接,类型转换 2.行转列,列转行 3. 窗口函数(over,lead,lag等函数) 4.rank(行号函数)5. json解析函数 6.jdbc连接hive,企业级调优

    1. null值处理,子串,拼接,类型转换 (1) 空字段赋值(null值处理) 当表中的某个字段为null时,比如奖金,当你要统计一个人的总工资时,字段为null的值就无法处理,这个时候就可以使用N ...

  2. Hive| 压缩| 存储| 调优

    Hadoop压缩配置 修改Hadoop集群具有Snappy压缩方式: 查看hadoop支持的压缩方式 [kris@hadoop101 datas]$ hadoop checknative 将编译好的支 ...

  3. 大数据:Hive常用参数调优

    1.limit限制调整 一般情况下,Limit语句还是需要执行整个查询语句,然后再返回部分结果. 有一个配置属性可以开启,避免这种情况---对数据源进行抽样 hive.limit.optimize.e ...

  4. 数仓Hive和分布式计算引擎Spark多整合方式实战和调优方向

    @ 目录 概述 Spark on Hive Hive on Spark 概述 编译Spark源码 配置 调优思路 编程方向 分组聚合优化 join优化 数据倾斜 任务并行度 小文件合并 CBO 谓词下 ...

  5. Hive Tuning(五) 标准调优清单

    Hive的标准调优清单,我们可以对照着来做我们的查询优化!

  6. 基于CDH 5.9.1 搭建 Hive on Spark 及相关配置和调优

    Hive默认使用的计算框架是MapReduce,在我们使用Hive的时候通过写SQL语句,Hive会自动将SQL语句转化成MapReduce作业去执行,但是MapReduce的执行速度远差与Spark ...

  7. 【原创】大数据基础之Hive(5)性能调优Performance Tuning

    1 compress & mr hive默认的execution engine是mr hive> set hive.execution.engine;hive.execution.eng ...

  8. hive 调优手段

    调优手段 ()利用列裁剪 当待查询的表字段较多时,选取需要使用的字段进行查询,避免直接select *出大表的所有字段,以免当使用Beeline查询时控制台输出缓冲区被大数据量撑爆. ()JOIN避免 ...

  9. 大数据技术之_08_Hive学习_04_压缩和存储(Hive高级)+ 企业级调优(Hive优化)

    第8章 压缩和存储(Hive高级)8.1 Hadoop源码编译支持Snappy压缩8.1.1 资源准备8.1.2 jar包安装8.1.3 编译源码8.2 Hadoop压缩配置8.2.1 MR支持的压缩 ...

随机推荐

  1. cmake - 可执行文件

    1.生成可执行文件 add_executable(hello xxx.cpp xxxxx.cpp) ##根据文件xxx.cpp和xxxx.cpp生成可执行文件hello,但是这两个可执行文件如果依赖其 ...

  2. 一文彻底吃透MyBatis源码!!

    写在前面 随着互联网的发展,越来越多的公司摒弃了Hibernate,而选择拥抱了MyBatis.而且,很多大厂在面试的时候喜欢问MyBatis底层的原理和源码实现.总之,MyBatis几乎成为了Jav ...

  3. 初识分布式图数据库 Nebula Graph 2.0 Query Engine

    摘要:本文主要介绍 Query 层的整体结构,并通过一条 nGQL 语句来介绍其通过 Query 层的四个主要模块的流程. 一.概述 分布式图数据库 Nebula Graph 2.0 版本相比 1.0 ...

  4. 网络爬虫第一步:通用代码框架(python版)

    import requests def getHTMLText(url):     try:         r=requests.get(url,timeout=30)         r.rais ...

  5. 用python做youtube自动化下载器 代码

    目录 项目地址 思路 流程 1. post i. 先把post中的headers格式化 ii.然后把参数也格式化 iii. 最后再执行requests库的post请求 iv. 封装成一个函数 2. 调 ...

  6. JVM 源码分析(四):深入理解 park / unpark

    前言 Parker 源码调试与分析 park/unpark 原理总结 补充:jstack 命令和 kill 命令 前言 熟悉 Java 并发包的人一定对 LockSupport 的 park/unpa ...

  7. kubernets之pod的删除方式

    一 删除单个pod 1  删除指定命名空间的指定名称的pod k delete po kubia-manual -n defaultpod "kubia-manual" delet ...

  8. Windows DHCP最佳实践(四)

    这是Windows DHCP最佳实践和技巧的最终指南. 如果您有任何最佳做法或技巧,请在下面的评论中发布它们. 在本指南(四)中,我将分享以下DHCP最佳实践和技巧. 使用DHCP中继代理 防止恶意D ...

  9. Electron实用技巧-开机启动时隐藏主窗口,只显示系统托盘

    # 1 在桌面软件中,开机自启动是很常见的功能,在electron中也提供了很好的支持,以下是主要代码: //应用是否打包if (app.isPackaged) {  //设置开机启动  app.se ...

  10. ts类与修饰符

    最近在用egret做游戏,就接触到了ts,刚开始的时候觉得类挺难的,毕竟大多数的JavaScript工程师工作中不怎么需要用到这个,但是学起来就不愿意撒手了,真香! typescript其实是es6的 ...