スタンドアローンモードではなく、複数台のサーバーで動かす

一台ではえらく簡単だったんだけど

  • 複数台では結構つまづいた
  • できたけどうまく理解できていない
  • できたけど、もっと効率よくできるんじゃないか

などなどあったので記録を取っておく。

複数台のサーバーで(mapとかreduceを)動かすための鍵になるコマンドがあって、それはhadoop dfs。一台で動かしていると(たぶん)使わないコマンド。map&reduceするためのRuby(orその他のスクリプト)をhadoopで動かしたいサーバーに浸透させないといけない。scpなどのコマンドを使って、全てのサーバーにコピー...とかをやるわけではなく(同期とかを考えるとめんどくさそう...)、hadoopがその付近をやってくれるらしい。ついでに言うと、普通のファイルシステム上にコピーとかをしているわけではなく、hadoop上のファイルシステム上にコピーをするようです。そういうわけで「ファイルちゃんと置いてるのに何で読んでくれないの!!」ってなる人もいるかもしれないので注意(自分だった)。

hadoop上のファイルシステムにコピーとかそういう操作をやるコマンドがhadoop dfs。まず、どういう構成とかになっているかとか知りたいと思うので、ls likeな感じで

yasuhisa-y@XXX:/$ hadoop dfs -ls /user/yasuhisa-y
Found 3 items
-rw-r--r--   3 yasuhisa-y supergroup        172 2010-05-26 00:53 /user/yasuhisa-y/maper.rb
-rw-r--r--   3 yasuhisa-y supergroup        293 2010-05-26 00:53 /user/yasuhisa-y/reducer.rb
drwxr-xr-x   - yasuhisa-y supergroup          0 2010-05-26 03:08 /user/yasuhisa-y/word_count_file

としましょう。自分の場合は、すでにいくつか置いてあります。あ、松本研の人は、local wikiに書いてあるように

hadoop dfs -mkdir /user/(自分のアカウント名)

としておきましょう。tmpディレクトリ以下でやってもいいそうですが、再起動とかもしかかったら消えちゃいそうだし、自分の作っておきましょう(たぶん)。

hadoopのファイルシステム上にファイルを置きたい

「自分のローカルにあるファイルをhadoopのファイルシステム上に置きたい!」っていう場合は

hadoop dfs -put hoge.txt /user/yasuhisa-y

などとやると、hadoopのファイルシステム上の/user/yasuhisa-y以下にhoge.txtが配置されます。研究室には(master、slaveを含め)hadoop用のサーバーがいくつかありますが、この操作だけで、どのマシンからやっていてもhadoopのファイルシステム上の/user/yasuhisa-y以下にhoge.txtが配置されます。てら便利。

hadoopのファイルシステム上のファイルを見たい

普通のlinuxとかでcatするのと同じように

hadoop dfs -cat /user/yasuhisa-y/hoge.txt

とできて便利です。ファイルを見たいじゃなくて、ファイルそのものがローカルに欲しいという場合は

hadoop dfs -get /user/yasuhisa-y/hoge.txt .

などとやればカレントディレクトリにhoge.txtがfetchされてくるらしいです。

複数台のサーバー上でhadoopを回したい

これで準備は大体整った(はず)。色々あれこれと試行錯誤してみた結果、こんな感じだととりあえずうまくいきました。やっていることは、日本語版Wikipediaを分かち書きされたもの。このデータは、松本研の人ならhadoopのファイルシステムにすでに置かれています。そうじゃない人は自分で作るか、代替のデータを用意してください。

yasuhisa-y@cacao:/work/yasuhisa-y$ hadoop jar /usr/lib/hadoop/contrib/streaming/hadoop-*-streaming.jar \
 -input /nldata/jawiki -output word_count_file 100 -numReduceTasks 100 \
 -mapper "maper.rb" -reducer "reducer.rb" -file "maper.rb" -file "reducer.rb" 

昨日のエントリにid:mamorukさんがコメントしてくださった(http://d.hatena.ne.jp/syou6162/20100525/1274785616#c1274798747)ように、mapperとreducerのスクリプトをhadoopのファイルシステム上に置いていると、そっちを変更する度にhadoop dfs -rm & hadoop dfs -putしないといけないので激しく面倒です。しかし、hadoop側でこれを自動でやってくれる仕組みがあるそうで、-fileオプションを使うとうまくやってくれます。

さて、そうするとログに

10/05/26 11:30:26 INFO streaming.StreamJob: Tracking URL: http://XXX.naist.jp:50030/jobdetails.jsp?jobid=job_201005202253_0095

というような行があって、mapとreduceの進行状況をブラウザから見ることができます。こんな感じのグラフとかで見れて便利。
Hadoop job_201005202253_0097 on parsley
上のグラフと見ても分かるのですが、reducerはmapperのjobが100%完了しなくても動き始めます。まあ、数数えるだけだからmapper終わらなくってもreducer開始できますよね。動かないとかエラーが起こったときもここからtrackingできるらしいです(あるいは/var/log/hadoop以下にlogファイルがあるので、そっちでも)。

その他、いくつか箇条書きで書いていくと

  • mapperとreducerの数を"100 100"と指定すればmapperとreducerの数が指定できる...はず
    • と思ったけど、mapperは勝手に192個とかに設定されていて、reducerは1つに指定されていた
    • reducerの数に関しては"-numReduceTasks 100"とやって指定した
      • wikipediaくらいのデータだとreducer 1つだと待ってるのがだる(ry

reducerまでやった結果はoutputで指定したディレクトリに吐かれていて

yasuhisa-y@cacao:/work/yasuhisa-y$ hadoop dfs -ls /user/yasuhisa-y/word_count_file

で調べられますね。上ではreducer 100個指定したので、partなんとかってファイルが100個吐かれています。ローカルのファイルに一個ずつgetしてくるのはだるいので、rubyとか(なんでもいいですが)を使ってこんな感じでやれば取ってこれます。

yasuhisa-y@XXX:/work/yasuhisa-y$ ruby -e "(0..99).each{|i| system(\"hadoop dfs -get /user/yasuhisa-y/word_count_file/part-%000005d . \"%i) }"
yasuhisa-y@XXX:/work/yasuhisa-y$ ls
maper.rb    part-00006	part-00013  part-00020	part-00027  part-00034	part-00041  part-00048	part-00055  part-00062	part-00069  part-00076	part-00083  part-00090	part-00097
part-00000  part-00007	part-00014  part-00021	part-00028  part-00035	part-00042  part-00049	part-00056  part-00063	part-00070  part-00077	part-00084  part-00091	part-00098
part-00001  part-00008	part-00015  part-00022	part-00029  part-00036	part-00043  part-00050	part-00057  part-00064	part-00071  part-00078	part-00085  part-00092	part-00099
part-00002  part-00009	part-00016  part-00023	part-00030  part-00037	part-00044  part-00051	part-00058  part-00065	part-00072  part-00079	part-00086  part-00093	reducer.rb
part-00003  part-00010	part-00017  part-00024	part-00031  part-00038	part-00045  part-00052	part-00059  part-00066	part-00073  part-00080	part-00087  part-00094
part-00004  part-00011	part-00018  part-00025	part-00032  part-00039	part-00046  part-00053	part-00060  part-00067	part-00074  part-00081	part-00088  part-00095
part-00005  part-00012	part-00019  part-00026	part-00033  part-00040	part-00047  part-00054	part-00061  part-00068	part-00075  part-00082	part-00089  part-00096

こういう感じで、スタンドアローンな場合と複数台のサーバーで動かすときは大分やることが違ってくるので、わりとはまります。ということで、松本研のM1の人は自分がはまったところはblogとかにlogを書いて(ry。