hive 调优

2021-02-20  本文已影响0人  wong小尧

q1-q5搬运自:
https://www.jianshu.com/p/32faae7230d5

主要是tez模式(hue)的调优

Tez出现问题
Q1: java.lang.ArithmeticException: / by zero

Vertex failed, vertexName=Map 1, vertexId=vertex_1557110571873_0003_1_00, diagnostics=[Vertex vertex_1557110571873_0003_1_00 [Map 1] killed/failed due to:ROOT_INPUT_INIT_FAILURE, Vertex Input: tez initializer failed, vertex=vertex_1557110571873_0003_1_00 [Map 1], java.lang.ArithmeticException: / by zero
    at org.apache.hadoop.hive.ql.exec.tez.HiveSplitGenerator.initialize(HiveSplitGenerator.java:123)
    at org.apache.tez.dag.app.dag.RootInputInitializerManager$InputInitializerCallable$1.run(RootInputInitializerManager.java:278)
    at org.apache.tez.dag.app.dag.RootInputInitializerManager$InputInitializerCallable$1.run(RootInputInitializerManager.java:269)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.Subject.doAs(Subject.java:422)
    at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1920)
    at org.apache.tez.dag.app.dag.RootInputInitializerManager$InputInitializerCallable.call(RootInputInitializerManager.java:269)
    at org.apache.tez.dag.app.dag.RootInputInitializerManager$InputInitializerCallable.call(RootInputInitializerManager.java:253)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

解决
SET hive.tez.container.size = ;
默认值:-1
默认情况下,Tez将生成一个mapper大小的容器。这可以用来覆盖默认值。
配置文件:hive-site-xml
建议:不小于或者是yarn.scheduler.minimum-allocation-mb的倍数

Q2: map 0%卡住
解决

查看了一下hive中hive.map.aggr.hash.percentmemory属性的说明: 
Hive Map 端聚合的哈稀存储所占用虚拟机的内存比例。 
意思是说,当内存的Map大小,占到JVM配置的Map进程的25%的时候
(默认是50%),就将这个数据flush到reducer去,
以释放内存Map的空间。 
错误原因:Map端聚合时hash表所占用的内存比例默认为0.5,这个值超过可用内存大小,导致内存溢出。

Q3: java.lang.NoClassDefFoundError: com/esotericsoftware/kryo/Serializer

ERROR : Vertex failed, vertexName=Map 1, vertexId=vertex_1558679295627_0001_1_00, diagnostics=[Vertex vertex_1558679295627_0001_1_00 [Map 1] killed/failed due to:ROOT_INPUT_INIT_FAILURE, Vertex Input: tez initializer failed, vertex=vertex_1558679295627_0001_1_00 [Map 1], java.lang.NoClassDefFoundError: com/esotericsoftware/kryo/Serializer at org.apache.hadoop.hive.ql.exec.tez.HiveSplitGenerator.initialize(HiveSplitGenerator.java:107) at org.apache.tez.dag.app.dag.RootInputInitializerManager$InputInitializerCallable$1.run(RootInputInitializerManager.java:278) at org.apache.tez.dag.app.dag.RootInputInitializerManager$InputInitializerCallable$1.run(RootInputInitializerManager.java:269) at java.security.AccessController.doPrivileged(Native Method) at javax.security.auth.Subject.doAs(Subject.java:422) at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1920) at org.apache.tez.dag.app.dag.RootInputInitializerManager$InputInitializerCallable.call(RootInputInitializerManager.java:269) at org.apache.tez.dag.app.dag.RootInputInitializerManager$InputInitializerCallable.call(RootInputInitializerManager.java:253) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Caused by: java.lang.ClassNotFoundException: com.esotericsoftware.kryo.Serializer at java.net.URLClassLoader.findClass(URLClassLoader.java:381) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ... 12 more

解决

# 切换指定目录,拷贝缺少jar
$ cd /opt/cloudera/parcels/CDH-5.11.0-1.cdh5.11.0.p0.34/jars
###################################################################
# 同步配置至所有Hiveserver2以及Hive Metastore Server、gateway机器;
###################################################################
cp ./kryo-2.22.jar ../lib/hive/auxlib/
# 如果在hive命令行执行,则不会报错,如果在hue中执行,需要重启hive。

Q4: Caused by: java.lang.OutOfMemoryError: Java heap space

Caused by: java.lang.OutOfMemoryError: Java heap space
 at org.apache.hadoop.hive.serde2.WriteBuffers.nextBufferToWrite(WriteBuffers.java:206)
 at org.apache.hadoop.hive.serde2.WriteBuffers.write(WriteBuffers.java:182)
 at org.apache.hadoop.hive.ql.exec.persistence.MapJoinBytesTableContainer$LazyBinaryKvWriter.writeValue(MapJoinBytesTableContainer.java:248)
 at org.apache.hadoop.hive.ql.exec.persistence.BytesBytesMultiHashMap.writeFirstValueRecord(BytesBytesMultiHashMap.java:574)
 at org.apache.hadoop.hive.ql.exec.persistence.BytesBytesMultiHashMap.put(BytesBytesMultiHashMap.java:229)
 at org.apache.hadoop.hive.ql.exec.persistence.MapJoinBytesTableContainer.putRow(MapJoinBytesTableContainer.java:288)

解决
https://mapr.com/support/s/article/How-to-change-Tez-container-heapsize?language=en_US

修改配置:
<property>
  <name>tez.am.resource.memory.mb</name>
  <value>2048</value>
</property>

Q5 Caused by: org.apache.hadoop.ipc.RemoteException(org.apache.tez.dag.api.TezException): App master already running a DAG

Caused by: org.apache.hadoop.ipc.RemoteException(org.apache.tez.dag.api.TezException): App master already running a DAG
    at org.apache.tez.dag.app.DAGAppMaster.submitDAGToAppMaster(DAGAppMaster.java:1379)
    at org.apache.tez.dag.api.client.DAGClientHandler.submitDAG(DAGClientHandler.java:140)
    at org.apache.tez.dag.api.client.rpc.DAGClientAMProtocolBlockingPBServerImpl.submitDAG(DAGClientAMProtocolBlockingPBServerImpl.java:175)
    at org.apache.tez.dag.api.client.rpc.DAGClientAMProtocolRPC$DAGClientAMProtocol$2.callBlockingMethod(DAGClientAMProtocolRPC.java:7636)
    at org.apache.hadoop.ipc.ProtobufRpcEngine$Server$ProtoBufRpcInvoker.call(ProtobufRpcEngine.java:617)
    at org.apache.hadoop.ipc.RPC$Server.call(RPC.java:1073)
    at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2220)
    at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2216)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.Subject.doAs(Subject.java:422)
    at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1920)
    at org.apache.hadoop.ipc.Server$Handler.run(Server.java:2214)
添加配置;
[beeswax]
    max_number_of_sessions=10

Q6 java.lang.AbstractMethodError: org.codehaus.jackson.map.AnnotationIntrospector.findSerializer(Lorg/codehaus/jackson/map/introspect/Annotated;)Ljava/lang/Object;

java.lang.AbstractMethodError: org.codehaus.jackson.map.AnnotationIntrospector.findSerializer(Lorg/codehaus/jackson/map/introspect/Annotated;)Ljava/lang/Object;
    at org.codehaus.jackson.map.ser.BasicSerializerFactory.findSerializerFromAnnotation(BasicSerializerFactory.java:362)
    at org.codehaus.jackson.map.ser.BeanSerializerFactory.createSerializer(BeanSerializerFactory.java:252)
    at org.codehaus.jackson.map.ser.StdSerializerProvider._createUntypedSerializer(StdSerializerProvider.java:782)
    at org.codehaus.jackson.map.ser.StdSerializerProvider._createAndCacheUntypedSerializer(StdSerializerProvider.java:735)
    at org.codehaus.jackson.map.ser.StdSerializerProvider.findValueSerializer(StdSerializerProvider.java:344)
    at org.codehaus.jackson.map.ser.StdSerializerProvider.findTypedValueSerializer(StdSerializerProvider.java:420)
    at org.codehaus.jackson.map.ser.StdSerializerProvider._serializeValue(StdSerializerProvider.java:601)
    at org.codehaus.jackson.map.ser.StdSerializerProvider.serializeValue(StdSerializerProvider.java:256)
    at org.codehaus.jackson.map.ObjectMapper.writeValue(ObjectMapper.java:1604)
    at org.codehaus.jackson.jaxrs.JacksonJsonProvider.writeTo(JacksonJsonProvider.java:527)
    at com.sun.jersey.api.client.RequestWriter.writeRequestEntity(RequestWriter.java:300)
    at com.sun.jersey.client.urlconnection.URLConnectionClientHandler._invoke(URLConnectionClientHandler.java:204)
    at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:147)
    at org.apache.hadoop.yarn.client.api.impl.TimelineClientImpl$TimelineJerseyRetryFilter$1.run(TimelineClientImpl.java:226)
    at org.apache.hadoop.yarn.client.api.impl.TimelineClientImpl$TimelineClientConnectionRetry.retryOn(TimelineClientImpl.java:162)
    at org.apache.hadoop.yarn.client.api.impl.TimelineClientImpl$TimelineJerseyRetryFilter.handle(TimelineClientImpl.java:237)
    at com.sun.jersey.api.client.Client.handle(Client.java:648)
    at com.sun.jersey.api.client.WebResource.handle(WebResource.java:670)
    at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74)
    at com.sun.jersey.api.client.WebResource$Builder.post(WebResource.java:563)
    at org.apache.hadoop.yarn.client.api.impl.TimelineClientImpl.doPostingObject(TimelineClientImpl.java:472)
    at org.apache.hadoop.yarn.client.api.impl.TimelineClientImpl.doPosting(TimelineClientImpl.java:321)
    at org.apache.hadoop.yarn.client.api.impl.TimelineClientImpl.putEntities(TimelineClientImpl.java:301)
    at org.apache.tez.dag.history.logging.ats.ATSHistoryLoggingService.handleEvents(ATSHistoryLoggingService.java:358)
    at org.apache.tez.dag.history.logging.ats.ATSHistoryLoggingService.serviceStop(ATSHistoryLoggingService.java:233)
    at org.apache.hadoop.service.AbstractService.stop(AbstractService.java:221)
    at org.apache.hadoop.service.ServiceOperations.stop(ServiceOperations.java:52)
    at org.apache.hadoop.service.ServiceOperations.stopQuietly(ServiceOperations.java:80)
    at org.apache.hadoop.service.CompositeService.stop(CompositeService.java:157)
    at org.apache.hadoop.service.CompositeService.serviceStop(CompositeService.java:131)
    at org.apache.tez.dag.history.HistoryEventHandler.serviceStop(HistoryEventHandler.java:111)
    at org.apache.hadoop.service.AbstractService.stop(AbstractService.java:221)
    at org.apache.hadoop.service.ServiceOperations.stop(ServiceOperations.java:52)
    at org.apache.hadoop.service.ServiceOperations.stopQuietly(ServiceOperations.java:80)
    at org.apache.hadoop.service.ServiceOperations.stopQuietly(ServiceOperations.java:65)
    at org.apache.tez.dag.app.DAGAppMaster.stopServices(DAGAppMaster.java:1949)
    at org.apache.tez.dag.app.DAGAppMaster.serviceStop(DAGAppMaster.java:2140)
    at org.apache.hadoop.service.AbstractService.stop(AbstractService.java:221)
    at org.apache.tez.dag.app.DAGAppMaster$DAGAppMasterShutdownHook.run(DAGAppMaster.java:2438)
    at org.apache.hadoop.util.ShutdownHookManager$1.run(ShutdownHookManager.java:54)

解决

更改tez的jackson JAR为1.9.13版本

Q7: spark读取表为空,hue中有数据
hive --orcfiledump -d



查看s3文件生成目录,发现在表文件夹下面建个二级文件夹, 在内部才是数据块文件,与其他表产生的文件存放路径不一致。




查看表生成数据的过程,差异是由于直接使用了 union all操作插入语句

Hive on tez 中对insert union操作进行了优化,会并行输出到对应的表目录,为防止有相同名文件存在,所以为各自输出在表目录下各自设置了一个目录,里边存放执行结果

解决方案:
在运行前设置计算引擎为mr,运行速度会下降些,但生成的数据不会产生子目录,使用起来不会出错。
set hive.execution.engine=mr

其他参数调优:搬运自https://www.cnblogs.com/yjt1993/p/11050791.html

一、AM、Container大小设置
1、tez.am.resource.memory.mb  #设置 tez AM容器内存
  默认值:1024  
  配置文件:tez-site.xml
  建议:不小于或者等于yarn.scheduler.minimum-allocation-mb值。
  

2、hive.tez.container.size  #设置 tez container内存
  默认值:-1
  默认情况下,Tez将生成一个mapper大小的容器。这可以用来覆盖默认值。
  配置文件:hive-site-xml
  建议:不小于或者是yarn.scheduler.minimum-allocation-mb的倍数
  
二、AM、Container JVM参数设置
1、tez.am.launch.cmd-opts  #设置 AM jvm,启动TEZ任务进程期间提供的命令行选项。
  默认值:-XX:+PrintGCDetails -verbose:gc -XX:+PrintGCTimeStamps -XX:+UseNUMA -XX:+UseParallelGC(用于GC),默认的大小:80%*tez.am.resource.memory.mb
  配置文件:tez-site.xml
  建议:不要在这些启动选项中设置任何xmx或xms,以便tez可以自动确定它们。
  

2、hive.tez.java.ops  #设置 container jvm
  默认值:Hortonworks建议“–server –Djava.net.preferIPv4Stack=true–XX:NewRatio=8 –XX:+UseNUMA –XX:UseG1G”,默认大小:80%*hive.tez.container.size
  说明:在hive 2.x的官方文档中没有找到这个参数。看有些博客里面有这个值。
  配置文件:hive-site.xml

3、tez.container.max.java.heap.fraction  #设置task/AM占用jvm内存大小的比例。
  默认值:0.8
  配置文件:tez-site.xml
  说明:这个值按具体需要调整,当内存不足时,一般都要调小。

三、Hive内存Map Join参数设置
1、tez.runtime.io.sort.mb  #设置输出排序内存大小
  默认值:100
  配置文件:tez-site.xml
  建议:40%*hive.tez.container.size,一般不超过2G
2、hive.auto.convert.join.noconditionaltask  #是否将多个mapjoin合并为一个
  默认值:true
  建议使用默认值。
  配置文件:hive-site.xml
3、hive.auto.convert.join.noconditionaltask.size  
  默认值:10000000  (10M)
  说明:这个参数使用的前提是hive.auto.convert.join.noconditionaltask值为true,多个mapjoin转换为1个时,所有小表的文件大小总和小于这个值,这个值只是限制输入的表文件的大小,并不代表实际mapjoin时hashtable的大小。 建议值:1/3* hive.tez.container.size
  配置文件:hive-site.xml
4、tez.runtime.unordered.output.buffer.size-mb  #如果不直接写入磁盘,使用的缓冲区大小
  默认值:100M
  建议:10%* hive.tez.container.size
  配置文件:tez-site.xml

5、tez.am.container.reuse.enabled  #容器重用
  默认值:true
  配置文件:tez-ste.xml

Hive常见错误以及优化调参

1. 在使用一些合并操作时,会有奇怪的报错

Error while compiling statement: FAILED: IllegalArgumentException Size requested for unknown type: java.util.Collection
这个报错可能是资源不够,使用tez模式速度快,但是更耗资源。
网上的解决方法:set hive.execution.engine=mr;
在待合并字段前加上distinct修饰,尽量不要有重复的。

2.join操作报错

Cartesian products are disabled for safety reasons. If you know what you are doing, please sethive.strict.checks.cartesian.product to false and that hive.mapred.mode is not set to 'strict' to proceed. Note that if you may get errors or incorrect results if you make a mistake while using some of the unsafe features.

通常是使用多个full outer join或者在使用其他join时,on没有去等于,而是大于小于之类,使用笛卡尔积cross join不加on也会有这个情况。
为了保障整个集群的稳定性,类似非全等的 Join 是默认禁止的,原因在异常代码中给出了:
FAILED: SemanticException Cartesian products are disabled for safety reasons
这样就可以避免因为大规模数据的 Join 导致网络瘫痪。

如果清晰的知道,非全等 Join 不会造成影响,那么可以修改这些配置来启动非全等 join 的操作。

set hive.strict.checks.cartesian.product=false;
set hive.mapred.mode=nonstrict;

3.分隔符使用;报错

Error: Error while compiling statement: FAILED: ParseException line 23:39 cannot recognize input near '<EOF>' '<EOF>' '<EOF>' in ……
concat_ws或者split中使用分号作为分隔符时,会报这样的错误。
在HUE或者数据平台里面可以跑通。
解决方法: 用分号的二进制 073来代替即可。
例如:concat_ws('\073',collect_set(data))

4.内存不够报错。

这种错误通常是集群机器比较少。
set hive.auto.convert.join = false;
考虑加上这个设置可以解决。
shuffle的时候加上这个设置不会把小的表放到内存中提速。

5.运行特别慢被kill

hive中可以增加或减少map/reduce数目,相当于改变并行的task数量,类似spark中的repartition,也相当于最后写进hive的小文件数量。
如果某个表只有一个文件,大小为120M,但包含几千万的记录,如果用1个map去完成这个任务,是比较耗时的,这种情况下,我们要考虑将这一个文件合理的拆分成多个,这样就可以用多个map任务去完成。

  set mapred.reduce.tasks=10;
  create table a_1 as select * from a distribute by rand(123);

这样会将a表的记录,随机的分散到包含10个文件的a_1表中,再用a_1代替上面sql中的a表,则会用10个map任务去完成。每个map任务处理约十分之一的数据。这样一定程度上也能解决数据倾斜。
由于字段数据的不均匀,按照某一字段分区reduce执行时会产生数据倾斜,此时在distribute by 后加一个随机数,按照随机数分区。

6.sql运行特别慢,最后报超时或者oom。

方法1:
如果是很简单的sql,可以考虑设置:
set hive.fetch.task.conversion=none;
有时候特别慢很简单的sql取不出数据,先执行上面的设置试试。
fetch task = 不启动MapReduce,直接读取本地文件输出结果。
这个属性有三个可选的值:
none:关闭fetch task优化
minimal:只在select 、使用分区列过滤、带有limit的语句上进行优化
more:在minimal的基础上更加强大了,select不仅仅可以是
,还可以单独选择几列,并且filter也不再局限于分区字段,同时支持虚拟列(别名)

方法2:
有时候确实是太慢了,可以考虑增加并行度
hive.exec.parallel参数控制在同一个sql中的不同的job是否可以同时运行,默认为false.

select r1.a
from (
   select t.a from table1 t join table2 s on t.a=s.b) r1 
   join 
   (select s.b from table2 t join table1 s on t.a=s.b) r2 
   on (r1.a=r2.b);

1 当参数为false的时候,三个job是顺序的执行
set hive.exec.parallel=false;
2 但是可以看出来其实两个子查询中的sql并无关系,可以并行的跑
set hive.exec.parallel=true;
在资源充足的时候hive.exec.parallel会让那些存在并发job的sql运行得更快,但同时消耗更多的资源

方法3:
调整hive.exec.orc.split.strategy参数
hive.exec.orc.split.strategy参数控制在读取ORC表时生成split的策略。

对于一些较大的ORC表,可能其footer较大,ETL策略可能会导致其从hdfs拉取大量的数据来切分split,甚至会导致driver端OOM,因此这类表的读取建议使用BI策略。
对于一些较小的尤其有数据倾斜的表(这里的数据倾斜指大量stripe存储于少数文件中),建议使用ETL策略。
另外,spark.hadoop.mapreduce.input.fileinputformat.split.minsize参数可以控制在ORC切分时stripe的合并处理。具体逻辑是,当几个stripe的大小小于spark.hadoop.mapreduce.input.fileinputformat.split.minsize时,会合并到一个task中处理。可以适当调小该值,以此增大读ORC表的并发。

方法4:
考虑一些调优
控制map和reduce的数量:
map、reduce数据量,对效率影响较大,因为在启动和初始化阶段是很耗费时间和资源的。
 map数普遍是通过执行时长来确认的,至少应当保证每个map执行时长在1分钟以上,太短的话意味着大量重复的jvm启用和销毁。具体设置要根据具体任务来处理,有些任务占用cpu大,有些占用io大。
reduce是可以直接设置的,reduce数过多:生成很多小文件,可能会影响下一个任务输入。

控制mapper数量

Map输入合并小文件
对应参数:
set mapred.max.split.size=256000000; #每个Map最大输入大小
set mapred.min.split.size.per.node=100000000; #一个节点上split的至少的大小
set mapred.min.split.size.per.rack=100000000; #一个交换机下split的至少的大小
set hive.input.format=org.apache.Hadoop.hive.ql.io.CombineHiveInputFormat; #执行Map前进行小文件合并

在开启了org.apache.hadoop.hive.ql.io.CombineHiveInputFormat后,一个data node节点上多个小文件会进行合并,合并文件数由mapred.max.split.size限制的大小决定。

mapred.min.split.size.per.node决定了多个data node上的文件是否需要合并~

mapred.min.split.size.per.rack决定了多个交换机上的文件是否需要合并~

输出合并(控制下一个任务的map数量)

set hive.merge.mapfiles = true #在Map-only的任务结束时合并小文件
set hive.merge.mapredfiles = true #在Map-Reduce的任务结束时合并小文件
set hive.merge.size.per.task = 256 * 1000 * 1000 #合并文件的大小
set hive.merge.smallfiles.avgsize=16000000 #当输出文件的平均大小小于该值时,启动一个独立的map-reduce

控制reducer的数据量

set mapred.reduce.tasks=12; #直接指定reducer个数
set hive.exec.reducers.bytes.per.reducer=1073741824; #调整每个reduce处理的数据量来控制reducer,默认1000^3=1G
hive.exec.reducers.max; #每个任务最大的reduce数,默认为999

什么情况下只会有一个reduce:
很多时候会发现,任务重不管数据量有多大,不管有没有调整reduce的个数,任务一直都只有一个reduce
(1) 数据量小于hive.exec.reducers.bytes.per.reducer参数值的情况外
(2) 没有group by的汇总
(3) 用了order by

上一篇下一篇

猜你喜欢

热点阅读