Pivotal Knowledge Base

フォローする

Hash join をする時に Hive 子プロセスの最大ヒープサイズの増加ができない

環境

  • PHD 3.0
  • HIVE 0.14.0

事象

ユーザが大規模なhash joinを伴うHiveクエリを実行すると、次のエラーが発生することがある。

rg.apache.hadoop.hive.ql.exec.mapjoin.MapJoinMemoryExhaustionException: 2015-08-24 09:22:56        Processing rows:       1300000 Hashtable size: 1299999 Memory usage:  1844338856        percentage:    0.966
        at org.apache.hadoop.hive.ql.exec.mapjoin.MapJoinMemoryExhaustionHandler.checkMemoryStatus(MapJoinMemoryExhaustionHandler.java:91)
        at org.apache.hadoop.hive.ql.exec.HashTableSinkOperator.processOp(HashTableSinkOperator.java:251)
        at org.apache.hadoop.hive.ql.exec.Operator.forward(Operator.java:815)
        at org.apache.hadoop.hive.ql.exec.SelectOperator.processOp(SelectOperator.java:84)
        at org.apache.hadoop.hive.ql.exec.Operator.forward(Operator.java:815)
        at org.apache.hadoop.hive.ql.exec.TableScanOperator.processOp(TableScanOperator.java:95)
        at org.apache.hadoop.hive.ql.exec.mr.MapredLocalTask.startForward(MapredLocalTask.java:404)
        at org.apache.hadoop.hive.ql.exec.mr.MapredLocalTask.startForward(MapredLocalTask.java:375)
        at org.apache.hadoop.hive.ql.exec.mr.MapredLocalTask.executeInProcess(MapredLocalTask.java:341)
        at org.apache.hadoop.hive.ql.exec.mr.ExecDriver.main(ExecDriver.java:744)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at org.apache.hadoop.util.RunJar.run(RunJar.java:221)
        at org.apache.hadoop.util.RunJar.main(RunJar.java:136)

このエラーでネット検索するとhive.mapred.local.memの値を増加するという対策が出てくるが、コンテナのログを参照するとhive.mapred.local.memの値に関わらず、Mapタスクに起動されたローカルのJVMプロセスの最大ヒープサイズが2GBのままであることが判明する。

2015-08-24 07:01:50     Starting to launch local task to process map join;      maximum memory = 1908932608

原因

Hash joinを実行する時に、HiveのMapタスクはhadoop jarを用いてExecDriverというMain Classを実行するために、新しいJVMを起動する。

13868 [main] INFO  org.apache.hadoop.hive.ql.exec.mr.MapredLocalTask  - Executing: /usr/bin/hadoop jar /u/applic/data/hdfs1/yarn/nm-local-dir/filecache/119/hive-exec-0.14.0.3.0.0.0-249.jar org.apache.hadoop.hive.ql.exec.mr.ExecDriver -localtask -plan file:/u/applic/data/hdfs9/yarn/nm-local-dir/usercache/mucha1/appcache/application_1440185851071_29920/container_1440185851071_29920_01_000002/tmp/mucha1/67d4be51-0b6f-486c-bf83-38fe8ecd4356/hive_2015-08-25_21-31-50_516_3577978971253935151-1/-local-10005/plan.xml   -jobconffile file:/u/applic/data/hdfs9/yarn/nm-local-dir/usercache/mucha1/appcache/application_1440185851071_29920/container_1440185851071_29920_01_000002/tmp/mucha1/67d4be51-0b6f-486c-bf83-38fe8ecd4356/hive_2015-08-25_21-31-50_516_3577978971253935151-1/-local-10006/jobconf.xml
2015-08-25 21:31:54,416 INFO  [main] mr.MapredLocalTask (MapredLocalTask.java:executeInChildVM(286)) - Executing: /usr/bin/hadoop jar /u/applic/data/hdfs1/yarn/nm-local-dir/filecache/119/hive-exec-0.14.0.3.0.0.0-249.jar org.apache.hadoop.hive.ql.exec.mr.ExecDriver -localtask -plan file:/u/applic/data/hdfs9/yarn/nm-local-dir/usercache/mucha1/appcache/application_1440185851071_29920/container_1440185851071_29920_01_000002/tmp/mucha1/67d4be51-0b6f-486c-bf83-38fe8ecd4356/hive_2015-08-25_21-31-50_516_3577978971253935151-1/-local-10005/plan.xml   -jobconffile file:/u/applic/data/hdfs9/yarn/nm-local-dir/usercache/mucha1/appcache/application_1440185851071_29920/container_1440185851071_29920_01_000002/tmp/mucha1/67d4be51-0b6f-486c-bf83-38fe8ecd4356/hive_2015-08-25_21-31-50_516_3577978971253935151-1/-local-10006/jobconf.xml

HiveがJVMを起動する前に「HADOOP_HEAPSIZE」の環境変数をhive.mapred.local.memの値に設定するが、/usr/bin/hadoopが現在のHADOOP_HEAPSIZEの 値に書き換えてしまう。

./ql/src/java/org/apache/hadoop/hive/ql/exec/mr/MapredLocalTask.java のソースコードから、hive.mapred.local.mem が設定されていると HiveがHADOOP_HEAPSIZE を設定することが分かる。

      int hadoopMem = conf.getIntVar(HiveConf.ConfVars.HIVEHADOOPMAXMEM);
     if (hadoopMem == 0) {
       // remove env var that would default child jvm to use parent's memory
       // as default. child jvm would use default memory for a hadoop client
       variables.remove(HADOOP_MEM_KEY);
     } else {
       // user specified the memory for local mode hadoop run
       console.printInfo(" set heap size\t" + hadoopMem + "MB");
       variables.put(HADOOP_MEM_KEY, String.valueOf(hadoopMem));
     }
HiveConf.java:482:    HIVEHADOOPMAXMEM("hive.mapred.local.mem", 0),

他方、/usr/bin/hadoopは、/etc/hadoop/conf/hadoop-env.shをソースして既存の HADOOP_HEAPSIZE 設定に書き換えてしまう。結果として、hive.mapred.local.mem パラメーターは何の効果もないこととなる。

# The maximum amount of heap to use, in MB. Default is 1000.
export HADOOP_HEAPSIZE="2048"

回避策

Ambari の「Hadoop Maximum Heap Size」パラメーターにて/etc/hadoop/conf/hadoop-env.sh の HADOOP_HEAPSIZE を増やして Node Manager のサービスを再起動する。

 

 

コメント

Powered by Zendesk