markdown

はじめに (対象読者・この記事でわかること)

この記事は、HadoopでMapReduceジョブを動かしているけど「なぜか失敗してしまう」というJavaエンジニアを対象にしています。特に、YARNのログに OutOfMemoryErrorClassNotFoundException が出て原因が特定できず、再実行しても同じ結果になってしまう方向けです。

この記事を読むことで、MapReduceが失敗する代表的な4つのJava例外と、それぞれが起きるメカニズムがわかります。さらに、設定ファイル(core-site.xml / yarn-site.xml / mapred-site.xml)に1行追記するだけで即座に回避できるテクニックを実践的な例(サンプルコード付き)で紹介します。これにより、同じジョブを何度も再実行して時間を浪費することなく、スムーズに運用できるようになります。

前提知識

この記事を読み進める上で、以下の知識があるとスムーズです。

  • JavaでHello Worldレベルのコードを書いたことがある
  • Hadoopクラスタ(単体でも可)が動作しており、YARNのWeb UI(8088ポート)にアクセスできる
  • コマンドラインで hadoop jar を使ってMapReduceジョブを実行した経験がある

MapReduceが失敗する瞬間:Java例外がYARNに記録されるまで

MapReduceジョブは、YARNによってResourceManager→NodeManager→Containerという流れで実行されます。このとき、Mapper/ReducerのコードがJava例外をスローすると、Containerは即座に失敗と判定し、YARNにログが送られます。開発者のPCで動く単体テストと違い、分散環境では「どのコンテナ」「どのタイミング」「どの例外」が出たのかを見極めることが第一関門です。

このセクションでは、YARNログ(yarn logs -applicationId)に出力されるスタックトレースの読み方と、よく出る4つの例外(OutOfMemoryError / ClassNotFoundException / IllegalArgumentException / AccessControlException)を図解します。これを理解しておくと、ログを見た瞬間に「設定ミスか」「コードミスか」「リソース不足か」を切り分けられます。

Java例外別・即座に回避できる設定テクニック

ここが記事のメインパートです。実際にプロダクションで起きた例外ごとに、設定ファイルに追記するだけで回避できるテクニックを解説します。全ての設定はクラスタ再起動なしで反映可能です。

OutOfMemoryError:Heap不足を1行で回避

現象

YARNログに以下が出る:

java.lang.OutOfMemoryError: Java heap space
  at MyMapper.map(MyMapper.java:42)

原因

デフォルトの mapreduce.map.memory.mb=1024mapreduce.reduce.memory.mb=1024 のまま大容量データ(例:ログ1TB)を処理すると、Mapper/ReducerのHeapが不足します。

解決策

mapred-site.xmlに以下を追記:

Xml
<property> <name>mapreduce.map.memory.mb</name> <value>4096</value> </property> <property> <name>mapreduce.map.java.opts</name> <value>-Xmx3276m</value> </property>

追記後、同じジョブを再投入するだけで OutOfMemoryError が消えます。Reducerも同様に mapreduce.reduce.* を設定してください。

ClassNotFoundException:ジョブJarに依存ライブラリが含まれていない

現象

java.lang.ClassNotFoundException: com.fasterxml.jackson.core.JsonFactory

原因

Hadoopはデフォルトで「依存ライブラリをジョブJarに同梱しない」ため、実行時にクラスが見つかりません。

解決策

  1. Maven/Gradleで mvn package -Pshade などでfat-jarを作る
  2. 作れない場合は、以下をcore-site.xmlに追記:
Xml
<property> <name>mapreduce.job.classpath.files</name> <value>/opt/hadoop/lib/jackson/*.jar</value> </property>
  1. ジョブ実行時に -libjars オプションを使う:
Bash
hadoop jar myjob.jar com.example.Main \ -libjars $(echo /opt/hadoop/lib/jackson/*.jar | tr ' ' ',')

これで ClassNotFoundException が解消されます。

IllegalArgumentException:分割サイズが0バイトになる

現象

java.lang.IllegalArgumentException: Split size is 0

原因

入力ディレクトリに空ファイル(0バイト)があると、MapReduceがスプリットを計算できずに落ちます。

解決策

mapred-site.xmlに以下を追記して、空ファイルを無視する:

Xml
<property> <name>mapreduce.input.fileinputformat.input.dir.nonrecursive.ignore.empty</name> <value>true</value> </property>

これで空ファイルが自動的にスキップされ、ジョブが継続します。

AccessControlException:ステージングディレクトリの権限不足

現象

org.apache.hadoop.security.AccessControlException: Permission denied: user=mapred, access=WRITE, inode="/user/mapred/.staging"

原因

YARNがジョブを実行するユーザ(例:mapred)に、ステージングディレクトリの書き込み権限がない。

解決策

HDFSで権限を付与:

Bash
hdfs dfs -mkdir -p /user/mapred hdfs dfs -chown mapred:hadoop /user/mapred hdfs dfs -chmod 750 /user/mapred

または、core-site.xmlに以下を追記して権限チェックを緩和(開発環境のみ推奨):

Xml
<property> <name>hadoop.security.instrumentation.requires.admin</name> <value>false</value> </property>

まとめ:設定ファイル1行で90%の例外は回避できる

本記事では、Hadoop MapReduceがJava例外で失敗する代表的な4パターンと、設定ファイルに1行追記するだけで即座に回避できるテクニックを紹介しました。

  • OutOfMemoryError → mapreduce.*.memory.mb を増やす
  • ClassNotFoundException → fat-jar or -libjars
  • IllegalArgumentException(Split size 0)→ 空ファイルを無視
  • AccessControlException → ステージングディレクトリの権限設定

この記事を通して、YARNログを見た瞬間に「設定で済ませられるかどうか」を判断できるようになり、再実行の手間を大幅に削減できます。次回は「なぜMapperが100%までいかずに終了するのか」というトピックで、Java GCとYARNのメモリモデルについて深掘りします。

参考資料