Tag Archives: Hadoop

Hadoop tips

hadoopのバージョンもついに1になった(リンク)。そこで久々に試してみたついでに、複数マシン(cluster構成)でmap-reduceジョブを行う際に気をつけるパラメーターについて新たに知ったことをメモしておくことにする。なお、相変わらずhdfsは使っていないので、それ関係の情報は無い。

  • core-site.xml
  • パフォーマンス向上のために下記パラメーターの値を調整する。

    1. fs.inmemory.size.mb
    2. io.sort.facto
    3. io.sort.mb
    4. io.file.buffer.size
  • mapred-site.xml
  • 下記パラメーターは、クラスタを構成する全てのマシンから共通に見えるパス(シェアディレクトリ)を設定する。

    1. mapred.system.dir
    2. mapred.temp.dir
    3. mapreduce.jobtracker.staging.root.dir
  • lib/native/Linux-amd64-64
  • map-reduce処理を担うプログラム中で必要なライブラリはこのディレクトリ下に配置する。
    mapred-site.xml中のmapred.child.java.optsパラメーターで-Djava.library.pathを設定しても効かなかった。

参考文献はCluster SetupMapReduce Tutorial

Hadoop java.library.path 問題

今回はSWIGを利用してC++で書かれたプログラムをHadoop MapReduceから使おうとした。
これを参考にして以下のような処理を実行。

swig -c++ -java -package yayamamo -outdir yayamamo -noproxy hoge.i
g++ -fPIC -c HogeFuga.cpp
g++ -fPIC -c hoge_wrap.cxx -I/usr/local/java/include -I/usr/local/java/include/linux
g++ -shared HogeFuga.o hoge_wrap.o -o hoge.so

これに倣った実行テストプログラムはめでたく動作、かと思われたが、実はC++で書かれたそのサブルーチンは引数に文字列 (= char * ) を取り、それを直接書き換えるもので、javaから呼び出すとその引数である文字列は変化しない。javaのStringオブジェクトの中身を直接書き換えるようにはなっていないから。なので、C++側で、引数で与えられた文字列を変更した結果が戻り値となる新規ルーチンを用意。

続いて Hadoop で使うための環境を整える。ここを見るとどうやら mapred-site.xml で mapred.child.java.optsプロパティの値に -Djava.library.path=/home/mycompany/lib を加えるだけのように思われた。しかし、ここに設定するとジョブが失敗する。それまで正常に動作していたものも。Hadoop 本体を実行するするスクリプト内で設定している JAVA_LIBRARY_PATH と競合している模様。仕方ないので、Hadoop にバンドルされているネイティブコードライブラリの置かれるディレクトリ lib/native/Linux-amd64-64 以下に先ほど生成した hoge.so をコピー。問題無く動作することを確認。

hadoop取り敢えずまとめ

hadoop ver. 0.20.0 について

下記の項目に留意して効率アップをする

  • プログラム中でのconf.setNumReduceTasks(<INT>)の記述
  • プログラム中でのcombineの工夫
  • プログラム中でのconf.setCompressMapOutput(true);conf.setMapOutputCompressorClass(DefaultCodec.class);の記述
  • core-site.xmlでのio.sort.factorの設定(100など)

また、hdfsを使わない時の設定として留意する点は、core-site.xmlt中においてfs.default.nameをfile:///とすることとともに、mapred-site.xml中に、mapred.system.dirとmapred.temp.dirに対して、cluster環境下(=複数ノードに渡る構成)でも物理的に同一パスを指すようにする。

cluster環境下で、各ノードのローカルディスクが殆ど無いような環境では、/tmp下(=各ノードの物理ディスク領域)にそれぞれのノードで別々のnfsパスへのシンボリックリンクを張る。物理的に同じディスク領域が指定されるとディスクアクセスが適切に動作しない。

hadoop & eclipse

hadoopアプリの効率的な開発のためにeclipseを導入。
hadoop pluginがhadoopに梱包されているのでそれをeclipseのpluginフォルダにコピーする。

適切に初期設定をすると、eclipse内からhdfsが閲覧できたり、hadoopアプリを簡単にデバッグできるようになる。
とはいえ、hadoopバージョンアップに完全に追随できていない部分があるから、pluginの提供する機能の一部が使えない。

例えば、Project Explorerの、自分が実行させたいソースコードのファイル名の上で右クリックして「Run As」で表示される、「Run on Hadoop」は効かない。
今回はここを参考にしてみた。

因みに、hdfsを利用しないでhadoopのmap/reduceを走らせる時は、core-site.xml (0.20.0)かhadoop-site.xml (0.19.2)のfs.default.nameをfile:///とする。

Hadoop io.compress / distributive

Version 0.20.0 (java 1.6.0_13 on SunOS 5.10)の話。
Mapの出力を圧縮するのにGzipCodecを利用したら何故か動作せず。
BZip2CodecならOK。
と思ったら、こちらもダメ。(コンパイルは通るのだが、実際に実行すると途中でコケる)
DefaultCodec でようやく問題無く動作。
まだ色々難しいのだろうか。

distributiveなMap関数の場合はCombinerを使う。

追記
どうやらSunOS 5.10/sparcだから問題があるようだ。
Java で Sun だから、むしろこちらの方が望ましいかと思いきや。
util.NativeCodeLoader で Loaded the native-hadoop library と表示されるのは x86 で、sparcマシンでは失敗する。

追記2
Reduce Taskの数を複数にするためには conf/mapred-site.xml に mapred.tasktracker.reduce.tasks.maximum の数を大きくするだけではなく、実際のソースコードに conf.setNumReduceTasks(30) の様に設定する必要がある。