本文介紹Hive作業異常的排查方法和解決方法。
異常排查
如果客戶端遇到作業異?;蛐阅艿葐栴},您可以按照如下步驟進行排查:
查看Hive客戶端日志。
Hive CLI命令行提交的作業客戶端日志位于集群或Gateway節點的/tmp/hive/$USER/hive.log或者/tmp/$USER/hive.log。
Hive Beeline或者JDBC提交的作業日志位于HiveServer服務日志中(一般位于/var/log/emr/hive或者/mnt/disk1/log/hive目錄)。
查看Hive作業提交的YARN Application日志,使用yarn命令可以獲取日志。
yarn logs -applicationId application_xxx_xxx -appOwner userName
內存問題引起的報錯
Container內存不足引起的OOM
報錯日志:java.lang.OutOfMemoryError: GC overhead limit exceeded
或者java.lang.OutOfMemoryError: Java heap space
。
解決方法:調大Container的內存,Hive on MR作業需要同時調大JVM Heap Size。
Hive on MR:在YARN服務的配置頁面,單擊mapred-site.xml頁簽,調大maper和reducer的內存。
mapreduce.map.memory.mb=4096 mapreduce.reduce.memory.mb=4096
同時修改mapreduce.map.java.opts和mapreduce.reduce.java.opts的JVM參數
-Xmx
為mapreduce.map.memory.mb和mapreduce.reduce.memory.mb的80%。mapreduce.map.java.opts=-Xmx3276m (其他參數保持不變) mapreduce.reduce.java.opts=-Xmx3276m (其他參數保持不變)
Hive on Tez
如果Tez container內存不足,則在Hive服務的配置頁面,單擊hive-site.xml頁簽,調大Tez container內存。
hive.tez.container.size=4096
如果Tez am內存不足,則在Tez服務的配置頁面,單擊tez-site.xml頁簽,調大Tez am內存。
tez.am.resource.memory.mb=4096
Hive on Spark:在Spark服務的
spark-defaults.conf
中調大Spark Executor內存。spark.executor.memory=4g
因Container內存使用過多被YARN Kill
報錯日志:Container killed by YARN for exceeding memory limits
。
原因分析:Hive Task使用的內存(包括JVM堆內和堆外內存,以及子進程)超過了作業向YARN申請的內存。比如Hive on MR作業的Map Task JVM進程heap size(mapreduce.map.java.opts=-Xmx4g)超過了YARN內存申請量(mapreduce.map.memory.mb=3072,3G),會導致Container被YARN NodeManager Kill。
解決方法:
Hive on MR作業可增大mapreduce.map.memory.mb和mapreduce.reduce.memory.mb參數值,并確保大于mapreduce.map.java.opts和mapreduce.reduce.java.opts的JVM參數
-Xmx
值的1.25倍及以上。Hive on Spark作業可增大spark.executor.memoryOverhead參數值,并確保大于spark.executor.memory參數值的25%及以上。
SortBuffer配置太大導致OOM
報錯日志:
Error running child: java.lang.OutOfMemoryError: Java heap space
at org.apache.hadoop.mapred.MapTask$MapOutputBuffer.init(MapTask.java:986)
原因分析:Sort Buffer Size超過了Hive Task Container Size,例如:Container內存配了1300 MB,但Sortbuffer配了1024 MB。
解決方法:調大Container內存,或調小Sortbuffer。
tez.runtime.io.sort.mb (Hive on Tez)
mapreduce.task.io.sort.mb (Hive on MR)
部分GroupBy語句引起的OOM
報錯日志:
22/11/28 08:24:43 ERROR Executor: Exception in task 1.0 in stage 0.0 (TID 0)
java.lang.OutOfMemoryError: GC overhead limit exceeded
at org.apache.hadoop.hive.ql.exec.GroupByOperator.updateAggregations(GroupByOperator.java:611)
at org.apache.hadoop.hive.ql.exec.GroupByOperator.processHashAggr(GroupByOperator.java:813)
at org.apache.hadoop.hive.ql.exec.GroupByOperator.processKey(GroupByOperator.java:719)
at org.apache.hadoop.hive.ql.exec.GroupByOperator.process(GroupByOperator.java:787)
at org.apache.hadoop.hive.ql.exec.Operator.forward(Operator.java:897)
at org.apache.hadoop.hive.ql.exec.SelectOperator.process(SelectOperator.java:95)
at org.apache.hadoop.hive.ql.exec.Operator.forward(Operator.java:897)
at org.apache.hadoop.hive.ql.exec.TableScanOperator.process(TableScanOperator.java:130)
at org.apache.hadoop.hive.ql.exec.MapOperator$MapOpCtx.forward(MapOperator.java:148)
at org.apache.hadoop.hive.ql.exec.MapOperator.process(MapOperator.java:547)
原因分析:GroupBy的HashTable占用太多內存導致OOM。
解決方法:
減小Split Size至128 MB、64 MB或更小,增大作業并發度:
mapreduce.input.fileinputformat.split.maxsize=134217728
或mapreduce.input.fileinputformat.split.maxsize=67108864
。增大Mapper、Reducer的并發度。
增大Container的內存。具體方法,請參見Container內存不足引起的OOM。
讀取Snappy文件出現OOM
原因分析:LogService等服務寫入的標準Snappy文件和Hadoop生態的Snappy文件格式不同,EMR默認處理的是Hadoop修改過的Snappy格式,處理標準格式時會報錯OutOfMemoryError。
解決方法:對Hive作業配置如下參數。
set io.compression.codec.snappy.native=true;
元數據相關報錯
Drop大分區表超時
報錯日志:
FAILED: Execution ERROR, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask. org.apache.thrift.transport.TTransportException: java.net.SocketTimeoutException: Read timeout
原因分析:作業異常的可能原因是表分區太多,Drop耗時較長,導致Hive Metastore client網絡超時。
解決方法:
在EMR控制臺Hive服務的配置頁面,單擊hive-site.xml頁簽,調大Client訪問metastore的超時時間。
hive.metastore.client.socket.timeout=1200s
批量刪除分區,例如多次執行帶條件的分區。
alter table [TableName] DROP IF EXISTS PARTITION (ds<='20220720')
insert overwrite
動態分區導致作業失敗
報錯日志:通過insert overwrite
操作動態分區或執行類似存在insert overwrite
操作的作業時,出現Exception when loading xxx in table
報錯,HiveServer日志中出現了以下報錯日志。
Error in query: org.apache.hadoop.hive.ql.metadata.HiveException: Directory oss://xxxx could not be cleaned up.;
原因分析:元數據和數據不一致,元數據中存在某個分區的記錄,但數據存儲系統中沒有該路徑,導致使用cleanup方法的時候報錯找不到路徑。
解決方法:您可以嘗試修復元數據問題之后再重新執行作業。
Hive讀表或者刪除表時報錯java.lang.IllegalArgumentException: java.net.UnknownHostException: emr-header-1.xxx
原因分析:當EMR集群使用DLF統一元數據或者統一meta數據庫(舊版功能)時,創建的數據庫初始路徑是EMR當前集群的HDFS路徑(例如hdfs://master-1-1.xxx:9000/user/hive/warehouse/test.db
或者hdfs://emr-header-1.cluster-xxx:9000/user/hive/warehouse/test.db
)。Hive表路徑會繼承數據庫路徑,同樣也會使用當前集群的HDFS路徑(例如hdfs://master-1-1.xxx:9000/user/hive/warehouse/test.db/test_tbl
)。當啟用一個新EMR集群,同時使用Hive讀寫舊集群創建的Hive表或者數據庫時,新集群可能無法連接舊集群或者因舊集群已釋放,會出現java.net.UnknownHostException異常。
解決方法:
方法1:如果確認Hive表數據是臨時或者測試數據,可以嘗試修改Hive表路徑為某個OSS路徑,并且再次調用drop table或drop database命令。
-- Hive SQL alter table test_tbl set location 'oss://bucket/not/exists' drop table test_tbl; alter table test_pt_tbl partition (pt=xxx) set location 'oss://bucket/not/exists'; alter table test_pt_tbl drop partition pt=xxx); alter database test_db set location 'oss://bucket/not/exists' drop datatabase test_db
方法2:如果確認Hive表數據是有效數據,但在新集群上無法訪問。此時EMR舊集群上的Hive表數據保存在HDFS上,可以先嘗試將 HDFS數據轉移到OSS上,并且創建新表。
hadoop fs -cp hdfs://emr-header-1.xxx/old/path oss://bucket/new/path hive -e "create table new_tbl like old_tbl location 'oss://bucket/new/path'"
Hive UDF和第三方包
Hive lib目錄下放置三方包導致沖突
原因分析:在Hive lib目錄($HIVE_HOME/lib)下放置三方包或者替換Hive包經常會導致各種沖突問題,請避免此類操作。
解決方法:把放在$HIVE_HOME/lib里的三方包移除,恢復替換為原始的Hive JAR包。
Hive無法使用reflect函數
原因分析:在Ranger鑒權開啟的情況下可能無法使用reflect函數。
解決方法:將reflect函數從黑名單移除,在hive-site.xml
中配置。
hive.server2.builtin.udf.blacklist=empty_blacklist
自定義UDF導致作業運行慢
原因分析:Hive作業運行慢,但未發現異常日志,可能原因是Hive自定義UDF性能存在問題。
解決方法:可以通過對Hive task進行thread dump定位問題,根據thread dump發現的性能熱點針對性優化自定義UDF。
引擎兼容問題
Hive和Spark時區不一致導致結果不一致
異常現象:Hive的from_unix_time時區固定為UTC,而Spark使用的是本地時區,如果兩者的時區不一致會導致結果不一致。
解決方法:修改Spark時區為UTC,在Spark SQL里面插入如下代碼:
set spark.sql.session.timeZone=UTC;
或者修改Spark配置文件,添加新的配置:
spark.sql.session.timeZone=UTC
歷史Hive版本缺陷
Hive on Spark打開動態分區執行慢(已知缺陷)
原因分析:Hive開源版本的缺陷,Beeline的方式把spark.dynamicAllocation.enabled打開了,導致Hive在計算Shuffle的Partition的時候總是算成1。
解決方法:Hive on Spark作業關閉動態資源伸縮或者使用Hive on Tez。
spark.dynamicAllocation.enabled=false
打開dynamic.partition.hashjoin后tez報錯(已知缺陷)
報錯日志:
Vertex failed, vertexName=Reducer 2, vertexId=vertex_1536275581088_0001_5_02, diagnostics=[Task failed, taskId=task_1536275581088_0001_5_02_000009, diagnostics=[TaskAttempt 0 failed, info=[Error: Error while running task ( failure ) : attempt_1536275581088_0001_5_02_000009_0:java.lang.RuntimeException: java.lang.RuntimeException: cannot find field _col1 from [0:key, 1:value]
at org.apache.hadoop.hive.ql.exec.tez.TezProcessor.initializeAndRunProcessor(TezProcessor.java:296)
at org.apache.hadoop.hive.ql.exec.tez.TezProcessor.run(TezProcessor.java:250)
原因分析:Hive開源版本缺陷。
解決方法:臨時解決方案是關閉配置。
hive.optimize.dynamic.partition.hashjoin=false
MapJoinOperator報錯NullPointerException(已知缺陷)
報錯日志:
原因分析:開啟了hive.auto.convert.join.noconditionaltask會導致報錯。
解決方法:關閉相關配置。
hive.auto.convert.join.noconditionaltask=false
Hive on Tez報錯IllegalStateException(已知缺陷)
報錯日志:
java.lang.RuntimeException: java.lang.IllegalStateException: Was expecting dummy store operator but found: FS[17]
at org.apache.hadoop.hive.ql.exec.tez.TezProcessor.initializeAndRunProcessor(TezProcessor.java:296)
at org.apache.hadoop.hive.ql.exec.tez.TezProcessor.run(TezProcessor.java:250)
at org.apache.tez.runtime.LogicalIOProcessorRuntimeTask.run(LogicalIOProcessorRuntimeTask.java:374)
at org.apache.tez.runtime.task.TaskRunner2Callable$1.run(TaskRunner2Callable.java:73)
at org.apache.tez.runtime.task.TaskRunner2Callable$1.run(TaskRunner2Callable.java:61)
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:1730)
at org.apache.tez.runtime.task.TaskRunner2Callable.callInternal(TaskRunner2Callable.java:61)
at org.apache.tez.runtime.task.TaskRunner2Callable.callInternal(TaskRunner2Callable.java:37)
at org.apache.tez.common.CallableWithNdc.call(CallableWithNdc.java:36)
原因分析:Hive開源版本缺陷,在開啟Hive am reuse之后出現,目前EMR Hive暫未解決該問題。
解決方法:在單個作業層面把Tez ApplicationMaster reuse功能關掉。
set tez.am.container.reuse.enabled=false;
其他異常
select count(1)
結果為0
原因分析:select count(1)
使用的是Hive表統計信息(statistics),但這張表的統計信息不準確。
解決方法:修改配置不使用統計信息。
hive.compute.query.using.stats=false
或者使用analyze命令重新統計表統計信息。
analyze table <table_name> compute statistics;
在自建ECS上提交Hive作業異常
在自建ECS上提交Hive作業(不在EMR產品范圍內),會出現不可預期報錯。請使用EMR Gateway集群或者使用EMR-CLI自定義部署Gateway環境。更多信息,請參見使用EMR-CLI自定義部署Gateway環境。
數據傾斜導致的作業異常
異常現象:
Shuffle數據把磁盤打滿。
某些Task執行時間特別長。
某些Task或Container出現OOM。
解決方法:
打開Hive skewjoin優化。
set hive.optimize.skewjoin=true;
增大Mapper、Reducer的并發度。
增大Container的內存。具體方法,請參見Container內存不足引起的OOM。
報錯“Too many counters: 121 max=120”,該如何處理?
問題描述:使用Tez或MR引擎,在使用Hive SQL執行作業時報錯。
報錯分析:當前作業的counters數量超過默認的counters限制。
解決方法:您可以在EMR控制臺YARN服務的配置頁簽,搜索mapreduce.job.counters.max參數,調大該參數值,修改完后重新提交Hive作業,如果使用Beeline或者JDBC提交作業,需要重啟HiveServer服務。