您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 质量控制/管理 > 大数据性能优化之Hive优化
Hive性能优化1.概述本人在工作中总结Hive的常用优化手段和在工作中使用Hive出现的问题。下面开始本篇文章的优化介绍。2.介绍首先,我们来看看hadoop的计算框架特性,在此特性下会衍生哪些问题?数据量大不是问题,数据倾斜是个问题。jobs数比较多的作业运行效率相对比较低,比如即使有几百行的表,如果多次关联多次汇总,产生十几个jobs,耗时很长。原因是mapreduce作业初始化的时间是比较长的。sum,count,max,min等UDAF,不怕数据倾斜问题,hadoop在map端的汇总合并优化,使数据倾斜不成问题。count(distinct),在数据量大的情况下,效率较低,如果是多count(distinct)效率更低,因为count(distinct)是按groupby字段分组,按distinct字段排序,一般这种分布方式是很倾斜的。举个例子:比如男uv,女uv,像淘宝一天30亿的pv,如果按性别分组,分配2个reduce,每个reduce处理15亿数据。面对这些问题,我们能有哪些有效的优化手段呢?下面列出一些在工作有效可行的优化手段:好的模型设计事半功倍。解决数据倾斜问题。减少job数。设置合理的mapreduce的task数,能有效提升性能。(比如,10w+级别的计算,用160个reduce,那是相当的浪费,1个足够)。了解数据分布,自己动手解决数据倾斜问题是个不错的选择。sethive.groupby.skewindata=true;这是通用的算法优化,但算法优化有时不能适应特定业务背景,开发人员了解业务,了解数据,可以通过业务逻辑精确有效的解决数据倾斜问题。数据量较大的情况下,慎用count(distinct),count(distinct)容易产生倾斜问题。对小文件进行合并,是行至有效的提高调度效率的方法,假如所有的作业设置合理的文件数,对云梯的整体调度效率也会产生积极的正向影响。优化时把握整体,单个作业最优不如整体最优。而接下来,我们心中应该会有一些疑问,影响性能的根源是什么?3.性能低下的根源hive性能优化时,把HiveQL当做M/R程序来读,即从M/R的运行角度来考虑优化性能,从更底层思考如何优化运算性能,而不仅仅局限于逻辑代码的替换层面。RAC(RealApplicationCluster)真正应用集群就像一辆机动灵活的小货车,响应快;Hadoop就像吞吐量巨大的轮船,启动开销大,如果每次只做小数量的输入输出,利用率将会很低。所以用好Hadoop的首要任务是增大每次任务所搭载的数据量。Hadoop的核心能力是parition和sort,因而这也是优化的根本。观察Hadoop处理数据的过程,有几个显著的特征:数据的大规模并不是负载重点,造成运行压力过大是因为运行数据的倾斜。jobs数比较多的作业运行效率相对比较低,比如即使有几百行的表,如果多次关联对此汇总,产生几十个jobs,将会需要30分钟以上的时间且大部分时间被用于作业分配,初始化和数据输出。M/R作业初始化的时间是比较耗时间资源的一个部分。在使用SUM,COUNT,MAX,MIN等UDAF函数时,不怕数据倾斜问题,Hadoop在Map端的汇总合并优化过,使数据倾斜不成问题。COUNT(DISTINCT)在数据量大的情况下,效率较低,如果多COUNT(DISTINCT)效率更低,因为COUNT(DISTINCT)是按GROUPBY字段分组,按DISTINCT字段排序,一般这种分布式方式是很倾斜的;比如:男UV,女UV,淘宝一天30亿的PV,如果按性别分组,分配2个reduce,每个reduce处理15亿数据。数据倾斜是导致效率大幅降低的主要原因,可以采用多一次Map/Reduce的方法,避免倾斜。最后得出的结论是:避实就虚,用job数的增加,输入量的增加,占用更多存储空间,充分利用空闲CPU等各种方法,分解数据倾斜造成的负担。4.配置角度优化我们知道了性能低下的根源,同样,我们也可以从Hive的配置解读去优化。Hive系统内部已针对不同的查询预设定了优化方法,用户可以通过调整配置进行控制,以下举例介绍部分优化的策略以及优化控制选项。4.1列裁剪Hive在读数据的时候,可以只读取查询中所需要用到的列,而忽略其它列。例如,若有以下查询:SELECTa,bFROMqWHEREe10;在实施此项查询中,Q表有5列(a,b,c,d,e),Hive只读取查询逻辑中真实需要的3列a、b、e,而忽略列c,d;这样做节省了读取开销,中间表存储开销和数据整合开销。裁剪所对应的参数项为:hive.optimize.cp=true(默认值为真)4.2分区裁剪可以在查询的过程中减少不必要的分区。例如,若有以下查询:SELECT*FROM(SELECTTa1,COUNT(1)FROMTGROUPBYa1)subqWHEREsubq.prtn=100;#(多余分区)SELECT*FROMT1JOIN(SELECT*FROMT2)subqON(T1.a1=subq.a2)WHEREsubq.prtn=100;查询语句若将“subq.prtn=100”条件放入子查询中更为高效,可以减少读入的分区数目。Hive自动执行这种裁剪优化。分区参数为:hive.optimize.pruner=true(默认值为真)4.3JOIN操作在编写带有join操作的代码语句时,应该将条目少的表/子查询放在Join操作符的左边。因为在Reduce阶段,位于Join操作符左边的表的内容会被加载进内存,载入条目较少的表可以有效减少OOM(outofmemory)即内存溢出。所以对于同一个key来说,对应的value值小的放前,大的放后,这便是“小表放前”原则。若一条语句中有多个Join,依据Join的条件相同与否,有不同的处理方法。4.3.1JOIN原则在使用写有Join操作的查询语句时有一条原则:应该将条目少的表/子查询放在Join操作符的左边。原因是在Join操作的Reduce阶段,位于Join操作符左边的表的内容会被加载进内存,将条目少的表放在左边,可以有效减少发生OOM错误的几率。对于一条语句中有多个Join的情况,如果Join的条件相同,比如查询:INSERTOVERWRITETABLEpv_usersSELECTpv.pageid,u.ageFROMpage_viewpJOINuseruON(pv.userid=u.userid)JOINnewuserxON(u.userid=x.userid);如果Join的key相同,不管有多少个表,都会则会合并为一个Map-Reduce一个Map-Reduce任务,而不是‘n’个在做OUTERJOIN的时候也是一样如果Join的条件不相同,比如:INSERTOVERWRITETABLEpv_usersSELECTpv.pageid,u.ageFROMpage_viewpJOINuseruON(pv.userid=u.userid)JOINnewuserxon(u.age=x.age);Map-Reduce的任务数目和Join操作的数目是对应的,上述查询和以下查询是等价的:INSERTOVERWRITETABLEtmptableSELECT*FROMpage_viewpJOINuseruON(pv.userid=u.userid);INSERTOVERWRITETABLEpv_usersSELECTx.pageid,x.ageFROMtmptablexJOINnewuseryON(x.age=y.age);4.4MAPJOIN操作Join操作在Map阶段完成,不再需要Reduce,前提条件是需要的数据在Map的过程中可以访问到。比如查询:INSERTOVERWRITETABLEpv_usersSELECT/*+MAPJOIN(pv)*/pv.pageid,u.ageFROMpage_viewpvJOINuseruON(pv.userid=u.userid);可以在Map阶段完成Join,如图所示:相关的参数为:hive.join.emit.interval=1000hive.mapjoin.size.key=10000hive.mapjoin.cache.numrows=100004.5GROUPBY操作进行GROUPBY操作时需要注意一下几点:Map端部分聚合事实上并不是所有的聚合操作都需要在reduce部分进行,很多聚合操作都可以先在Map端进行部分聚合,然后reduce端得出最终结果。这里需要修改的参数为:hive.map.aggr=true(用于设定是否在map端进行聚合,默认值为真)hive.groupby.mapaggr.checkinterval=100000(用于设定map端进行聚合操作的条目数)有数据倾斜时进行负载均衡此处需要设定hive.groupby.skewindata,当选项设定为true是,生成的查询计划有两个MapReduce任务。在第一个MapReduce中,map的输出结果集合会随机分布到reduce中,每个reduce做部分聚合操作,并输出结果。这样处理的结果是,相同的GroupByKey有可能分发到不同的reduce中,从而达到负载均衡的目的;第二个MapReduce任务再根据预处理的数据结果按照GroupByKey分布到reduce中(这个过程可以保证相同的GroupByKey分布到同一个reduce中),最后完成最终的聚合操作。4.6合并小文件我们知道文件数目小,容易在文件存储端造成瓶颈,给HDFS带来压力,影响处理效率。对此,可以通过合并Map和Reduce的结果文件来消除这样的影响。用于设置合并属性的参数有:是否合并Map输出文件:hive.merge.mapfiles=true(默认值为真)是否合并Reduce端输出文件:hive.merge.mapredfiles=false(默认值为假)合并文件的大小:hive.merge.size.per.task=256*1000*1000(默认值为256000000)5.程序角度优化5.1熟练使用SQL提高查询熟练地使用SQL,能写出高效率的查询语句。场景:有一张user表,为卖家每天收到表,user_id,ds(日期)为key,属性有主营类目,指标有交易金额,交易笔数。每天要取前10天的总收入,总笔数,和最近一天的主营类目。解决方法1如下所示:常用方法INSERTOVERWRITETABLEt1SELECTuser_id,substr(MAX(CONCAT(ds,cat),9)ASmain_cat)FROMusersWHEREds=20120329//20120329为日期列的值,实际代码中可以用函数表示出当天日期GROUPBYuser_id;INSERTOVERWRITETABLEt2SELECTuser_id,sum(qty)ASqty,SUM(amt)ASamtFROMusersWHEREdsBETWEEN20120301AND20120329GROUPBYuser_idSELECTt1.user_id,t1.main_cat,t2.qty,t2.amtFROMt1JOINt2ONt1.user_id=t2.user_id下面给出方法1的思路,实现步骤如下:第一步:利用分析函数,取每个user_id最近一天的主营类目,存入临时表t1。第二步:汇总10天的总交易金额,交易笔数,存入临时表t2。第三步:关联t1,t2,得到最终的结果。解决方法2如下所示:优化方法SELECTuser_id,substr(MAX(CONCAT(ds,cat)),9)ASmain_cat,SUM(qty),SUM(amt)FROMusersWHEREdsBETWEEN20120301AND20120329GROUPBYuser_id在工作中我们总结出:方案2的开销等于方案1的第二步的开销,性能提升,由原有
本文标题:大数据性能优化之Hive优化
链接地址:https://www.777doc.com/doc-3603870 .html