本文介紹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。
grouping()使用異常
異常現象:在使用
grouping()函數時,遇到以下報錯資訊。grouping() requires at least 2 argument, got 1該錯誤表明
grouping()函數的調用參數解析異常。原因分析:此問題是由開源版本 Hive 的一個已知Bug導致的。Hive 對
grouping()函數的解析是大小寫敏感的。當使用小寫grouping()時,Hive 可能無法正確識別該函數,從而導致參數解析錯誤。解決方案:將 SQL 中的
grouping()函數改為大寫的GROUPING()即可解決問題。
引擎相容問題
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服務。