Hadoop入門者向けの注意点とかコツ(1)

修論やっと終わりました…死ぬかと思った。Hadoop MapReduceを利用してちょっとしたことをやったんですが、いろんなところで躓きました。Hadoopには「簡単 大規模 分散処理 なんだかすごい魔法の技術」っていうイメージを抱いていましたが、ぜんぜんそんなことないです。実装すごい大変でした。これからHadoopMapReduceをやってみようって人のために僕が躓いた所をまとめておきます。

最初に読むべきドキュメント

公式のチュートリアルを読みましょう。バージョンごとにドキュメントが違うので注意してください。英語が苦手だなって人は、日本語のドキュメントを読みましょう(ただし0.20まで)。でもHadoopはトラブルがガンガン起こると思うので、そんなときに英語も頑張って読むぞって人じゃないとHadoopでプログラミングするのは難しいです。

さらに詳しいドキュメントが欲しければオライリーの第二版Hadoop(通称象本)、またはHadoop徹底入門を読みましょう。

Hadoop 第2版

Hadoop 第2版

Hadoop徹底入門

Hadoop徹底入門

それ以上の中級者だとNTTデータのHadoop報告書オライリーHadoop MapReduce デザインパターンですかね。

クラスタの構成

Hadoopをインストールします。OSはUNIX系統が必要です。cygwinを使えばWindowsでもいけるみたいですが、ややこしそうなのでLinuxがいいとおもいます。いろんなサイトをみてるとCentOS(Red Hat系)がよく使われていました。私はOpenSUSE11(Red Hat系?)を使いました。

Hadoopをダウンロードします。Hadoopのソフトウェア群をまとめたHadoopディストリビューションClouderaなんてものがありますが、これを使うとどこに何があるか分かりにくいので初めての人にはおすすめしません。Hadoopの公式からダウンロードしましょう。Hadoopのバージョンは0.23のアルファ版がいいと思います。0.20は安定版ですが古いAPIをメインに利用しているためプログラミングの段階で苦労します。

クラスタ構成時のポイントを書いておきます

  • もしEclispeでプログラミングしてテストするって方はHadoopの実行ユーザーをEclipseの実行ユーザーと同じにしておくといいです。
  • JDKは最初からインストールされてるOpenJDKではなく本家のものを使います。
    • インストールしたらupdate-alternativeまたはalternativeコマンドでjavaのバージョンを切り替えられるようにすると楽です。
    • OpenSUSE11ではOpenJDKが入ってる状態で本家のJDKを入れるとパソコンを再起動したときにフリーズしました。これはjexecというのが悪さをしていたようです。本家JDKをインストールした直後に/etc/init.d/rc1〜5で、jexecを起動しないようにしておきましょう。もし起動しなくなったら起動時のjexecでのハングをご覧ください。私はこの方法でもだめだったので、OSインストール時のディスクを使ってレスキューモードでHDD(/dev/sda2)をマウントし、/etc/init.d/rc1〜5をいじりました。
  • Hadoop本体を展開
  • 一時ファイルの場所を変更する
    • 一時ファイルはデフォルトでは/tmp以下に作成されますが、ここに作成したファイルは一定期間後に削除されるので一時ファイルの場所を変更しましょう。

擬似分散や2台以上で動かすのは苦労すると思います。問題が起こった場合、次の確認方法があります。

  1. ノードの起動時に問題が起こった場合、各ノードのログファイル/opt/hadoop/logs/ディレクトリをみます。
  2. 起動に成功していればジョブトラッカーやネームノードのWEB UIでタスクトラッカーの台数、データノードの台数が正しいか確認しましょう。きちんと起動しているにもかかわらず台数の表示がおかしいケースもあります。そういう時はサンプルプログラムを一度実行してみてください。

問題が起きやすいのはネットワーク周りとパーミッションです。ネットワーク周りは実験用の環境であれば各ノードのファイアーウォールを切っておくと楽です。パーミッションはローカルファイルシステムパーミッションだけではなく、HDFSパーミッションにも問題が起こります。

クラスタ構成を変更した場合はHDFSをフォーマットする必要があります。ここで注意点です。フォーマットする前には全ノードの一時ファイルを削除してから行いましょう。これでよくトラブルが起きます。一時ファイルはデフォルトだと/tmp/hadoop-*のディレクトリに入ってると思います。

クラスタを簡単に管理する

台数が増えるごとに管理が面倒になりますよね。そんなとき自分でスクリプトを書いたり、エイリアス環境変数を設定すると楽になります。

Hadoopの基本操作

エイリアスHadoopの記法操作を簡単にします。次の場所やコマンドを、~/.bashrcにaliasで登録しておくと楽です。

h='/opt/hadoop'  #Hadoop本体のディレクトリ

hadoop_conf='$h/conf'  #設定ファイルのディレクトリ
hadoop_log='$h/logs'  #ログファイルのディレクトリ
alias hadoop='$h/bin/hadoop' #Hadoopのバイナリファイル

alias h-sample='hadoop $h/bin/hadoop jar $h/hadoop-examples-*.jar pi ' #サンプルの実行

ファイルの同期を簡単にする

クラスタ間でhadoop/confや/etc/hostsなどを同期するのにrsyncを使ったbash、sync.shを書きました。これはマスターノードから利用することを想定しており、指定したファイルを/opt/hadoop/conf/slavesに記述されたホストに同期させます。

#!/bin/sh

#引数
# $1 送り元のファイル
# $2 送り先のファイル
# $3 ターゲットのuser


if [ "$1" = "" ] ;then
echo "\$1: 送り元を指定してください"
exit 1
fi

if [ "$2" = "" ] ;then
  send=$(echo "$1")
else
  send=$(echo "$2")
fi

if [ "$3" = "" ] ;then
 user=$(id -un)
else
 user=$(echo "$3")
fi

while read LINE;do
  run=$(echo "rsync -avr --delete $1 $user@$LINE:$send")
  echo $run
  $run

done < "/opt/hadoop/conf/slaves"

このスクリプトの使い方を示します。ディレクトリの場合は後ろに/をつけるのを忘れないで下さい。

sync.sh file_name #ファイルを同期
sync.sh directory_name/  #ディレクトリを同期

これを利用して/etc/hostsや/hadoop/confを同期させるには次のようにします。sync.shは適当なディレクトリに入れておいて、そのディレクトリに対して$script_homeという変数を設定しておきます。

alias sync-conf='$script_home/sync.sh $h/conf/'
alias sync-hosts='sudo $script_home/sync.sh /etc/hosts'

このコマンドをaliasに登録しておくと一瞬で/etc/hostsや/hadoop/confを全ノードに同期することができます。

HDFSのフォーマットを簡単に行う

HDFSを正しくフォーマットして使うには全ノードの一時ファイルを削除してからフォーマットする必要があります。これを簡単に行うスクリプトです。

#!/bin/sh

remove(){
	#$1にはファイル名が入る
	while read LINE;do
		echo $LINE
		removeAtNod $LINE
	done < "$1"
}

removeAtNod(){
	#$1にはノード名がはいる
	ssh -n $1 "rm -r /tmp/hadoop-*"
}

remove "/opt/hadoop/conf/masters"
remove "/opt/hadoop/conf/slaves"

/opt/hadoop/bin/hadoop namenode -format

以上です
第2回に続きます

追記 2/19 12:21

Cloudera の shiumachi さんからコメントをいただきました。私よりずっと詳しい方ですのでshiumachiさんの意見も参考にしてみてください。/tmpの件については記事の中に入れさせてもらいました。ありがとうございます!