HIVEMapJoin異常問題處理總結
問題描述
在跑hive作業的時候,偶爾會遇到下面的異常 FAILED: Execution Error, return code 3 from org.apache.hadoop.hive.ql.exec.mr.MapredLocalTask 。通過檢視日誌,你可以看到這是map join的問題,會看到Starting to launch local task to process map join; maximum memory = xxx,Execution failed with exit status: 3 等等這樣的日誌。在網上搜尋也可以看到一些問題的解釋,例如 stackoverflow上就有一個 http://stackoverflow.com/questions/22977790/hive-query-execution-error-return-code-3-from-mapredlocaltask
搜尋結果建議的解決方案
-
- set hive.auto.convert.join = false; 關閉mapjion
-
- 調小hive.smalltable.filesize,預設是25000000(在2.0.0版本中)
-
- hive.mapjoin.localtask.max.memory.usage 調大到0.999
-
- set hive.ignore.mapjoin.hint=false; 關閉忽略mapjoin的hints
原理及問題分析
MapJoin原理可以參見這裡,講的比較清楚。出現問題的地方就是MapredLocalTask這裡,在客戶端本地啟動一個Driver程式,掃描小表的資料,將其轉換成一個HashTable的資料結構,這個過程中在做記憶體檢查,即checkMemoryStatus的時候,丟擲了異常。我們看一下這裡的檢查點
double percentage = (double) usedMemory / (double) maxHeapSize;
String msg = Utilities.now() + " Processing rows: " + numRows + " Hashtable size: "
+ tableContainerSize + " Memory usage: " + usedMemory + " percentage: " + percentageNumberFormat.format(percentage);
console.printInfo(msg);
if(percentage > maxMemoryUsage) {
throw new MapJoinMemoryExhaustionException(msg);
}
跟當前程式的MaxHeap有關,跟當前程式的UsedMemory有關,跟引數maxMemoryUsage有關(hive.mapjoin.localtask.max.memory.usage),通過分析比較我們可以發現,上述的方案1和4,直接關閉mapjion,避免啟動MapredLocalTask,就不會出現這樣的check,進而不會出現問題;上述的方案2,減小join表的大小,進而減小UsedMemory,也可以解決這個問題;上面的方案3, 調大maxMemoryUsage,使記憶體充分利用,也可以解決這個問題。我們注意到maxHeapSize 這個引數,沒有針對性的解決方案
增加的一種解決方案,調大MapredLocalTask JVM啟動引數
解決方案還是需要考慮不影響效能。
調大MapredLocalTask 的JVM啟動引數,進而可以增加maxHeapSize,同樣也可以解決這個問題。如何去調大這個引數呢?通過檢視MapredLocalTask程式碼我們可以看到
jarCmd = hiveJar + " " + ExecDriver.class.getName();
String hiveConfArgs = ExecDriver.generateCmdLine(conf, ctx);
String cmdLine = hadoopExec + " jar " + jarCmd + " -localtask -plan " + planPath.toString()
+ " " + isSilent + " " + hiveConfArgs;
...
Map<String, String> variables = new HashMap<String, String>(System.getenv());
...
// Run ExecDriver in another JVM
executor = Runtime.getRuntime().exec(cmdLine, env, new File(workDir));
啟動新的ExecDriver,使用的是hadoop jar,系統環境引數繼承了父程式的系統環境變數(裡面邏輯有一些引數會覆蓋)。而hadoop jar 啟動java程式,記憶體引數會受哪些地方影響呢?如果沒有設定,受hadoop自身一些指令碼配置的影響;HADOOP_HEAPSIZE,如果設定了該變數,JVM引數就是-Xmx${HADOOP_HEAPSIZE}m ;如果不設定 ,就會受/usr/lib/hadoop-current/libexec/hadoop-config.sh裡面配置的JAVA_HEAP_MAX=-Xmx1000m 。有沒有印象?你使用hadoop jar啟動的一些程式引數都是-Xmx1000m, 如果注意觀察,ExecDriver這個程式也是這個引數。知道這個引數之後,可以在/usr/lib/hadoop-current/libexec/hadoop-config.sh 這裡將引數調大,例如設定JAVA_HEAP_MAX=-Xmx1408m 可以解決問題。
研究與思考
通過檢視checkMemoryStatus 的程式碼,我們可以看到,這個比較的邏輯不太合適,當前記憶體使用達到了一定閾值,並不代表記憶體不夠用,因為還有gc存在啊,如果gc之後還是超過了這個閾值,確實需要丟擲異常。基於這樣的分析,在HIVE JIRA上提了一個issue 並有相應的一些想法和patch。如果感興趣,歡迎討論交流,請戳HIVE-15221
相關文章
- 3大問題!Redis快取異常及處理方案總結Redis快取
- .net異常處理的效能問題
- 總結:整理 oracle異常錯誤處理 .Oracle
- EJB3的異常處理問題
- Python異常處理回顧與總結Python
- phptrycatch異常處理結構PHP
- Linux記憶體異常問題處理Linux記憶體
- 異常篇——異常處理
- Java 異常處理的誤區和經驗總結Java
- C++異常處理機制核心觀點總結C++
- symfony2中對異常的處理,個人總結
- SVN異常處理——禁止訪問
- 異常處理
- crontab導致CPU異常的問題分析及處理
- windows新增計劃任務異常--問題總結Windows
- 請問EJB容器如何處理異常
- [轉載] Java異常處理習題Java
- 瀏覽器相容問題處理總結瀏覽器
- 異常-throws的方式處理異常
- 異常處理與異常函式函式
- JavaScript 異常處理JavaScript
- ThinkPHP 異常處理PHP
- React 異常處理React
- 08、異常處理
- JAVA 異常處理Java
- JAVA異常處理Java
- Abp 異常處理
- oracle異常處理Oracle
- PowerShell 異常處理
- plsql異常處理SQL
- Swift 異常處理Swift
- JS異常處理JS
- app異常處理APP
- Oracle 處理異常Oracle
- MySQL異常處理MySql
- 異常處理 (轉)
- golang - 異常處理Golang
- 異常處理2