Hive on MR调优
当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,输入分片由三个参数决定:
参数名 默认值 备注
dfs.block.size 128M HDFS上数据块的大小
mapreduce.min.split.size 0 最小分片数
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文件输出数量
--用于mapper输出排序的内存大小,调大的话,会减少磁盘spill的次数,此时如果内存足够的话,一般都会显著提升性能
mapreduce.task.io.sort.mb(default:100)
--开始spill的缓冲池阀值,默认0.80,spill一般会在Buffer空间大小的80%开始进行spill
mapreduce.map.sort.spill.percent(default:0.80)
(3)combine(排序和合并/sort&merge)
--运行combiner的最低文件数,与reduce共用;调大来减少merge的次数,从而减少磁盘的操作;
mapreduce.task.io.sort.factor(default:10)
--spill的文件数默认情况下由三个的时候就要进行combine操作,最终减少磁盘数据;
min.num.spill.for.combine 默认是3
(4)压缩设置
--设置为true进行压缩,数据会被压缩写入磁盘,,压缩一般可以10倍的减少IO操作
mapreduce.map.output.compress(default:false)
--压缩算法,推荐使用SnappyCodec;
mapreduce.map.output.compress.codec(default:org.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端输出数据的获取
--mr程序reducer copy数据的线程数。当map很多并且完成的比较快的job的情况下调大,有利于reduce更快的获取属于自己部分的数据
mapreduce.reduce.shuffle.parallelcopies 默认5
(2)数据合并(sort&merge)
--reduce复制map数据的时候指定的内存堆大小百分比,适当的增加该值可以减少map数据的磁盘溢出,能够提高系统能。
mapreduce.reduce.shuffle.input.buffer.percent 默认0.70;
--reduce进行shuffle的时候,用于启动合并输出和磁盘溢写的过程的阀值。
--如果允许,适当增大其比例能够减少磁盘溢写次数,提高系统性能。同mapreduce.reduce.shuffle.input.buffer.percent一起使用。
mapreduce.reduce.shuffle.merge.percent 默认0.66;
(3)reduce处理以及写出操作
--reduce函数开始运行时,内存中的map输出所占的堆内存比例不得高于这个值,默认情况内存都用于reduce函数,也就是map输出都写入到磁盘
set mapreduce.reduce.input.buffer.percent 默认0.0;
--开始spill的map输出文件数阈值,小于等于0表示没有阈值,此时只由缓冲池比例来控制
set mapreduce.reduce.merge.inmem.threshold 默认1000;
--服务于reduce提取结果的线程数量
mapreduce.shuffle.max.threads 默认0;
--修改reducer的个数,可以通过job.setNumReduceTasks方法来进行更改。
mapreduce.job.reduces 默认为1;
(4)合理设置reduce数
reduce数决定参数
参数名 默认值 备注
hive.exec.reducers.bytes.per.reducer 1G 一个reduce数据量的大小
hive.exec.reducers.max 999 hive 最大的个数
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的启动时间。
--JVM重用特别是对于小文件场景或者task特别多的场景
set mapred.job.reuse.jvm.num.tasks=10; --启动JVM虚拟机时,传递给虚拟机的启动参数,表示这个 Java 程序可以使用的最大堆内存数,一旦超过这个大小,JVM 就会抛出 Out of Memory 异常,并终止进程。
--设置的是 Container 的内存上限,这个参数由 NodeManager 读取并进行控制,当 Container 的内存大小超过了这个参数值,NodeManager 会负责 kill 掉 Container。
--mapreduce.map.java.opts一定要小于mapreduce.map.memory.mb。
mapreduce.map.java.opts 默认 -Xmx200m;
mapreduce.map.memory.mb
--同上
mapreduce.reduce.java.opts;
mapreduce.map.java.opts; --是否启动map阶段的推测执行,其实一般情况设置为false比较好。可通过方法job.setMapSpeculativeExecution来设置。
mapreduce.map.speculative 默认为true;
--是否需要启动reduce阶段的推测执行,其实一般情况设置为fase比较好。可通过方法job.setReduceSpeculativeExecution来设置。
mapreduce.reduce.speculative 默认为true;
4 并行化
一个hive sql语句可能会转为多个mapreduce job,每一个job就是一个stage,这些 job 顺序执行,这个在hue的运行日志中也可以看到。但是有时候这些任务之间并不是是相互依赖的,如果集群资源允许的话,可以让多个并不相互依赖stage并发执行,这样就节约了时间,提高了执行速度,但是如果集群资源匮乏时,启用并行化反倒是会导致各个job相互抢占资源而导致整体执行性能的下降。
--开启任务并行执行
set hive.exec.parallel=true;
--同一个sql允许并行任务的最大线程数
set hive.exec.parallel.thread.number 默认为8;
HiveQL调优
1 利用分区表优化
分区表是在某一个或者某几个维度上对数据进行分类存储,一个分区对应于一个目录。在这中的存储方式,当查询时,如果筛选条件里有分区字段,那么hive只需要遍历对应分区目录下的文件即可,不用全局遍历数据,使得处理的数据量大大减少,提高查询效率。
当一个hive表的查询大多数情况下,会根据某一个字段进行筛选时,那么非常适合创建为分区表。
2 利用桶表优化
就是指定桶的个数后,存储数据时,根据某一个字段进行哈希后,确定存储再哪个桶里,这样做的目的和分区表类似,也是使得筛选时不用全局遍历所有的数据,只需要遍历所在桶就可以了。
hive.optimize.bucketmapJOIN=true;
hive.input.format=org.apache.hadoop.hive.ql.io.bucketizedhiveInputFormat;
hive.optimize.bucketmapjoin=true;
hive.optimize.bucketmapjoin.sortedmerge=true;
3 对于整个sql的优化
(1)where 条件优化
where只在map端阶段执行,不会在reduce阶段执行,尽早地过滤数据,减少每个阶段的数据量,对于分区表要加分区,同时只选择需要使用到的字段。
(2)join优化
① 优先过滤后再join,最大限度地减少参与join的数据量。
② 小表join大表原则
应该遵守小表join大表原则,原因是join操作的reduce阶段,位于join左边的表内容会被加载进内存,将条目少的表放在左边,可以有效减少发生内存溢出的几率。join中执行顺序是从做到右生成job,应该保证连续查询中的表的大小从左到右是依次增加的。
③ join on条件相同的放入一个job
hive中,当多个表进行join时,如果join on的条件相同,那么他们会合并为一个mapreduce job,所以利用这个特性,可以将相同的join on的放入一个job来节省执行时间。
select pt.page_id,count(t.url) PV
from rpt_page_type pt
join (select url_page_id,url from trackinfo where ds='2016-10-11' ) t on pt.page_id=t.url_page_id
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;
④Common/shuffle/Reduce JOIN
发生在reduce 阶段, 适用于大表 连接 大表(默认的方式)
⑤Map JOIN
连接发生在map阶段 ,适用于小表 连接 大表,大表的数据从文件中读取,小表的数据存放在内存中(hive中已经自动进行了优化,自动判断小表,然后进行缓存)
set hive.auto.convert.join=true;
⑥SMB JOIN,Sort -Merge -Bucket Join 对大表连接大表的优化,用桶表的概念来进行优化。在一个桶内发送生笛卡尔积连接(需要是两个桶表进行join)
set hive.auto.convert.sortmerge.join=true;
set hive.optimize.bucketmapjoin = true;
set hive.optimize.bucketmapjoin.sortedmerge = true;
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调优的更多相关文章
- 大数据学习day28-----hive03------1. null值处理,子串,拼接,类型转换 2.行转列,列转行 3. 窗口函数(over,lead,lag等函数) 4.rank(行号函数)5. json解析函数 6.jdbc连接hive,企业级调优
1. null值处理,子串,拼接,类型转换 (1) 空字段赋值(null值处理) 当表中的某个字段为null时,比如奖金,当你要统计一个人的总工资时,字段为null的值就无法处理,这个时候就可以使用N ...
- Hive| 压缩| 存储| 调优
Hadoop压缩配置 修改Hadoop集群具有Snappy压缩方式: 查看hadoop支持的压缩方式 [kris@hadoop101 datas]$ hadoop checknative 将编译好的支 ...
- 大数据:Hive常用参数调优
1.limit限制调整 一般情况下,Limit语句还是需要执行整个查询语句,然后再返回部分结果. 有一个配置属性可以开启,避免这种情况---对数据源进行抽样 hive.limit.optimize.e ...
- 数仓Hive和分布式计算引擎Spark多整合方式实战和调优方向
@ 目录 概述 Spark on Hive Hive on Spark 概述 编译Spark源码 配置 调优思路 编程方向 分组聚合优化 join优化 数据倾斜 任务并行度 小文件合并 CBO 谓词下 ...
- Hive Tuning(五) 标准调优清单
Hive的标准调优清单,我们可以对照着来做我们的查询优化!
- 基于CDH 5.9.1 搭建 Hive on Spark 及相关配置和调优
Hive默认使用的计算框架是MapReduce,在我们使用Hive的时候通过写SQL语句,Hive会自动将SQL语句转化成MapReduce作业去执行,但是MapReduce的执行速度远差与Spark ...
- 【原创】大数据基础之Hive(5)性能调优Performance Tuning
1 compress & mr hive默认的execution engine是mr hive> set hive.execution.engine;hive.execution.eng ...
- hive 调优手段
调优手段 ()利用列裁剪 当待查询的表字段较多时,选取需要使用的字段进行查询,避免直接select *出大表的所有字段,以免当使用Beeline查询时控制台输出缓冲区被大数据量撑爆. ()JOIN避免 ...
- 大数据技术之_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支持的压缩 ...
随机推荐
- Miller Rabin素数检测与Pollard Rho算法
一些前置知识可以看一下我的联赛前数学知识 如何判断一个数是否为质数 方法一:试除法 扫描\(2\sim \sqrt{n}\)之间的所有整数,依次检查它们能否整除\(n\),若都不能整除,则\(n\)是 ...
- Spark RDD批量写入Hbase
- Vue自动化路由(基于Vue-Router)开篇
vue自动化路由 好久不见~ 若羽又开篇Vue的内容了. 年初的时候发布了第一版的ea-router自动化路由库,欢迎大家安装使用.[Github地址] [npm地址] 经历一年的使用.还是发现了不少 ...
- 第1章 无所不在的JavaScript
traceur转码(编译)器 Babel转码(编译)器 JavaScript API 的核心组成部分:ECMASCcript, DOM, BOM 桌面应用:electron 移动应用:Apache C ...
- Java的nanoTime()方法
java有两个获取和时间相关的秒数方法,一个是广泛使用的 System.currentTimeMillis() 返回的是从一个长整型结果,表示毫秒. 另一个是 System.nanoTime() 返回 ...
- python -c 妙用
前言 python -c 命令还是有用的哈 正文 python的 -c 可以在命令行中调用 python 代码, 实际上 -c 就是 command 的意思 官方文档中解释为(节选自: python ...
- LeetCode 二分查找模板 I
模板 #1: int binarySearch(vector<int>& nums, int target){ if(nums.size() == 0) return -1; in ...
- Mac pycharm更换版本后打不开
1.第一步:先输入: cd /Applications/PyCharm.app/Contents/MacOS 2.第二步:查看无法打开pycharm的原因,需要输入:c./pycharm 3.第三 ...
- 从一次生产消费者的bug看看线程池如何增加线程
0 背景 某个闲来无事的下午,看到旧有的项目中,有个任务调度的地方都是同步的操作,就是流程A的完成依赖流程B,流程B的完成依赖流程C,按此类推. 作为一名垃圾代码生产者,QA的噩梦.故障报告枪手的我来 ...
- Java开发手册之编程规约
时隔一年多,再次开始更新博客,各位粉丝们久等了.大家是不是以为我像大多数开发者一样三分钟热度,坚持了一年半载就放弃了,其实不是.在过去的一年时间我学习了<Java编程思想>这本书,因为都是 ...