Asakusa Framework Advent Calendar 2014の9日目です。
今日はOutOfMemoryError(略称OOM)の話をしたいと思います。
AsakusaFWは分散処理を行うバッチアプリケーションのフレームワークであり、分散処理基盤としてHadoopを使っています。
分散処理を行う必要があるということは、それなりの大量データを対象としているということです。当然、大量データを限られたメモリーで処理するための工夫がされています。
Hadoopの素のコーディングでも、Mapper/ReducerでOOMになることは基本的に無いと思います。1レコードずつ処理していくので。
OOMになるのは、大抵はソート用(Shuffle)の領域が足りなくなったときだと思います。
この辺りはHadoopのチューニングとして、本にも出ているのではないかと思います。
AsakusaFWもHadoopを使っているので、Hadoop内の仕組みに関することではHadoopのチューニングをするしかありません。
もちろん、OOMに関してAsakusaFW固有で気を付けなければならない事もあります。
まず、Map系演算子は、基本的には大丈夫です。
演算子がMap系かReduce系かというのは演算子リファレンスの「性能特性」を見れば載っていますが、今回の話題に関して言えば、引数にjava.util.Listが有るか無いかです。
引数がListでない演算子(主にMap系演算子)では1レコードずつ処理されていくので、そのメソッド内でよほど大量にメモリーを使わなければOOMになることはありません。
有り得そうなのは、Operatorクラスのフィールドに(java.util.HashMapか何かで)大量にデータを保持することです。さすがにこれはOOMになる可能性があります。
引数にListが入っている演算子(Reduce系演算子の一部)はOOMに関する注意が必要です。例えばCoGroup演算子です。
Listにはグルーピングされた同一キーの全データが入ってきます。デフォルトでは、それらが全てメモリー上に載せられます。当然ながら、それが大量の場合はOOMになります。
大量になると分かった場合は、CoGroupの引数inputBufferにESCAPEを指定することで 全データをメモリーに載せるのを回避できます。
ただし、全データをメモリー上に載せるのと比べれば、処理速度が劣化します。
スモールジョブ実行エンジンだとHadoopクライアント上で実行されるので、HadoopクライアントのJavaVMのメモリー割り当てが少ないとOOMになる可能性があります。
また、バッファーサイズの設定を小さくしたり、スモールデータの判定の閾値を大きくしたりするとOOMになる可能性がありますね。
ただ、自分はAsakusaFWを使っていてCoGroup以外でOOMになったことはあまり記憶に無いです。(NPEはよく起こしますが^^;)