hadoopアドベントカレンダー2011 11日目 Hadoopのスレーブノードでのメモリ割当

クレジットカード現金化詐欺【業界人が教える口コミ情報】の12/11を担当するwyukawaです。

ネタもつきてきたので他人のふんどしで行きますw

今日はHadoopのスレーブノードでのメモリ割当について書きます。象本でいうと9章に書いてある話になります。

元ネタは下記にある以前Hadoopのトラブルシューティングに関する資料があったのでめもっとく - wyukawa’s blogで紹介した資料の日本語版です。

この資料はHadoopソースコードリーディング 第7回 Tickets, Mon, Nov 28, 2011 at 7:00 PM | Eventbriteでも発表されました。

この資料の中でHadoopのスレーブノードでのメモリ割当について書かれています。

資料のp19に以下のメモリ割当に関する式があります。この式はとても重要です。

Total RAM = (Mappers + Reducers) * Child Task Heap + DN heap + TT heap + 3G + RS heap + Other Service's heap

ちなみにRSはHBaseのRegion ServerのことなのでHBaseを使ってない人は無視してよいです。Other Service's heapもおいとくとHBaseを使っていない場合は

 (Mappers + Reducers) * Child Task Heap + DN heap + TT heap + 3G < 物理メモリ量

という状態になっている必要があります。

Mappersというのは1つのTaskTrackerによって実行されるmapタスクの最大数でmapred.tasktracker.map.tasks.maximumパラメータによって制御します。デフォルトは2タスクです。

Reducersというのは1つのTaskTrackerによって実行されるreduceタスクの最大数でmapred.tasktracker.reduce.tasks.maximumパラメータによって制御します。デフォルトは2タスクです。

Child Task HeapはTaskTrackerによって起動される子JVMに与えられるメモリ量のことで、mapred.child.java.optsパラメータで設定します。デフォルトは-Xmx200mつまり200mです。

DN heapはDataNodeが使用するメモリ量でhadoop-env.shのHADOOP_HEAPSIZEで設定します。デフォルトは1Gです。

TT heapはTaskTrackerが使用するメモリ量でhadoop-env.shのHADOOP_HEAPSIZEで設定します。デフォルトは1Gです。

3GはOSが使うメモリ量です。

つまり単純計算だと(2+2)*200m + 1G + 1G + 3G = 5.8Gより大きな物理メモリを搭載する必要があります。

まあこれぐらいの物理メモリを搭載していることは多いと思いますが、パラメータをいじってうっかり超えてしまったとなるとOutOfMemoryとなります。

あるジョブがうっかりメモリを使い切ってしまい他のジョブに悪影響を及ぼすかもしれません。

その対策としてmapred.child.ulimitパラメータでMapReduceの子プログラムに割り当てる仮想メモリの上限を指定するといいらしいというのがClouderaのニュースレターに書いてありました。

Hadoopでメモリ不足(out of memory)を回避するための方法の一つは、
mapred.child.ulimitパラメータでプロセスごとのメモリの上限を設定するこ
とです。このパラメータは、MapReduceの子プログラムに割り当てる仮想メモ
リの最大値をキロバイト単位で指定します。この値の範囲内でユーザのヒー
プとJVM自体の要求メモリを確保しなければならないため、この値は
mapred.child.java.optsで要求しているヒープサイズよりも必ず大きな値に
しなければなりません。タスクのヒープの上限値を効率よく設定するため、
mapred.child.ulimitの値は少なくともmapred.child.java.opts -Xmxで設定
した値の1.5倍より大きな値にすべきです。例えば、1GBのヒープを設定した
場合、mapred.child.ulimitを1.5GBに設定します。(もし CDH3u0より前の
バージョンを実行している場合、out of memoryを回避するためにulimitの値
をもっと大きく(-Xmx の2.5倍かそれ以上)する必要があるかもしれません)

機械学習 | 分析 | クラウド - Cloudera

mapred.child.ulimitパラメータで指定した値はulimit -vで設定されます。これを見て分かる通りLinux前提です。Windowsでは意味が無いです。まあWindowsで動かす人いないと思いますがw

これに限らずHadoopLinux系コマンドを使うのでWindowsで動かす場合はcygwinが必要になります。

閑話休題

ulimitコマンドがどこで実行されるかというとtaskjvm.shというシェルスクリプトの中です。

taskjvm.shというシェルスクリプトを実行することによってMapReduceジョブが走ります。

保存場所は下記のような感じです。[job-ID]はジョブID、[task-attempt-ID]はタスク試行IDです。ジョブID以下のディレクトリはジョブ実行後に削除されます。

${mapred.local.dir}/ttprivate/taskTracker/${user.name}/jobcache/[job-ID]/[task-attempt-ID]/taskjvm.sh

シェルの中身はこんな感じになります。

export JVM_PID=`echo $$`
export HADOOP_CLIENT_OPTS=...
export HADOOP_WORK_DIR=...
export HADOOP_TOKEN_FILE_LOCATION=...
export HADOOP_ROOT_LOGGER=...
export LD_LIBRARY_PATH=...
'ulimit' '-v' '1500000'

exec setsid '.../java' ... 'org.apache.hadoop.mapred.Child' ...

さて明日はどうしよ。