MacにHadoop環境を整える

mongoDBの勉強会でMapReduceの話が出てましたし、やはりHadoopは非常に気になります。
ということで、
Hadoop on MacOSX - Happy-Camper Street
MacでHadoopスタンドアローンモード - kj-kiのはてなダイアリー
MacHadoop環境を作る参考に、本棚に眠っていた

Software Design (ソフトウェア デザイン) 2010年 05月号 [雑誌]
Software Design (ソフトウェア デザイン) 2010年 05月号 [雑誌]
技術評論社 2010-04-17
売り上げランキング :


Amazonで詳しく見る
by G-Tools
Hadoopの実行テストの参考にしました。

やったこと

Hadoopを手に入れる

ここからソースを落とします。

$ wget http://apache.mirror.aussiehq.net.au//hadoop/core/stable/hadoop-0.20.2.tar.gz

Javaのバージョン確認

HadoopはJava6以上からサポートされているらしいです。
Oracle Blogs | Homepage

$java -version
java version "1.6.0_17"
Java(TM) SE Runtime Environment (build 1.6.0_17-b04-248)
Java HotSpot(TM) 64-Bit Server VM (build 14.3-b01-101, mixed mode)

$JAVA_HOMEについて

TOMCATJDKのホームディレクトリとして$JAVA_HOMEを参照します。
環境変数JAVA_HOMEとPATHの違い | JavaのQ&A【OKWave】
設定は

あたりを参考に.zshrc(.bashrc)辺りに

export JAVA_HOME=/Library/Java/Home
export PATH=$JAVA_HOEM/bin:$PATH

/Library/Java/Homeを調べると、確かに色々とリンクをはっていて、結局
/System/Library/Frameworks/JavaVM.framework/Version/1.6.0/Home
へリンクが張られていることを確認するのも楽しいですよ。

これでHadoopが動くようになりました。

/usr/local/hadoop/bin/hadoop -version
java version "1.6.0_17"
Java(TM) SE Runtime Environment (build 1.6.0_17-b04-248)
Java HotSpot(TM) 64-Bit Server VM (build 14.3-b01-101, mixed mode)

この段階でスタンドアロンモードを動かすことは可能ですが、今回は疑似分散モードまで試すので設定を続けます。

hadoopユーザーの作成

MacLinuxと違ってadduserコマンド一発でユーザーを作成したりグループの設定をしたりできなくて苦戦しました。
ここがかなり役立ちました。

sudo dscl . -list /Groups PrimaryGroupID | awk '{print $2}' | sort -rn
sudo dscl . -list /Users UniqueID | awk '{print $2}' | sort -rn 

参考サイトと同じく300番が空いていたのでそこに設定します。

$ sudo dscl . -create /Users/_hadoop UniqueID 300
$ sudo dscl . -create /Users/_hadoop RealName "Hadoop Service"
$ sudo dscl . -create /Users/_hadoop PrimaryGroupID 300
$ sudo dscl . -create /Users/_hadoop NFSHomeDirectory /Users/hadoop
$ sudo dscl . -create /Users/_hadoop Password "*"
$ sudo dscl . -append /Users/_hadoop RecordName hadoop
$ sudo /usr/sbin/createhomedir -b -u hadoop

linuxの時の癖で/home/hadoopにNFSHomeDirectoryに作ろうとしていて、うまくいきませんでした><
Macでは/Users/(user)ですね。
ところで、_hadoopである必要もないですね。/Users/hadoopでいいんじゃないかという。

公開鍵認証の設定

$su - hadoop
$ssh-keygen
$cd .ssh
$cat ssh id_rsa.pub >> authorized_keys

自分で作った公開鍵でアクセスにきたときに、認証するような設定です。
Macでは、システム環境設定⇒共有⇒リモートログインをチェックでsshdが起動します。

$ssh hadoop@localhost

でログインできればOKですね。

hadoopユーザでも${JAVA_HOME}の設定をします。というか、今回やることに関しては、こっちだけ設定しておけば大丈夫ですね。

$vim .bashrc
export JAVA_HOME=/Library/Java/Home
export PATH=$JAVA_HOME/bin:$PATH
$echo $JAVA_HOME
/Library/Java/Home

スタンドアロンモードでの起動

円周率計算のサンプルプログラムを動かしてみます。

$cd ${HADOOP_HOME}/bin/hadoop jar hadoop-0.20.2-examples.jar pi 1 1000
bin/hadoop jar hadoop-0.20.2-examples.jar pi 1 1000
Number of Maps  = 1
Samples per Map = 1000
Wrote input for Map #0
Starting Job
11/04/10 22:18:19 INFO jvm.JvmMetrics: Initializing JVM Metrics with processName=JobTracker, sessionId=
11/04/10 22:18:19 INFO mapred.FileInputFormat: Total input paths to process : 1
11/04/10 22:18:20 INFO mapred.JobClient: Running job: job_local_0001
11/04/10 22:18:20 INFO mapred.FileInputFormat: Total input paths to process : 1
11/04/10 22:18:20 INFO mapred.MapTask: numReduceTasks: 1
11/04/10 22:18:20 INFO mapred.MapTask: io.sort.mb = 100
11/04/10 22:18:20 INFO mapred.MapTask: data buffer = 79691776/99614720
11/04/10 22:18:20 INFO mapred.MapTask: record buffer = 262144/327680
11/04/10 22:18:20 INFO mapred.MapTask: Starting flush of map output
11/04/10 22:18:20 INFO mapred.MapTask: Finished spill 0
11/04/10 22:18:20 INFO mapred.TaskRunner: Task:attempt_local_0001_m_000000_0 is done. And is in the process of commiting
11/04/10 22:18:20 INFO mapred.LocalJobRunner: Generated 1000 samples.
11/04/10 22:18:20 INFO mapred.TaskRunner: Task 'attempt_local_0001_m_000000_0' done.
11/04/10 22:18:20 INFO mapred.LocalJobRunner:
11/04/10 22:18:20 INFO mapred.Merger: Merging 1 sorted segments
11/04/10 22:18:20 INFO mapred.Merger: Down to the last merge-pass, with 1 segments left of total size: 24 bytes
11/04/10 22:18:20 INFO mapred.LocalJobRunner:
11/04/10 22:18:20 INFO mapred.TaskRunner: Task:attempt_local_0001_r_000000_0 is done. And is in the process of commiting
11/04/10 22:18:20 INFO mapred.LocalJobRunner:
11/04/10 22:18:20 INFO mapred.TaskRunner: Task attempt_local_0001_r_000000_0 is allowed to commit now
11/04/10 22:18:20 INFO mapred.FileOutputCommitter: Saved output of task 'attempt_local_0001_r_000000_0' to file:/usr/local/hadoop/PiEstimator_TMP_3_141592654/out
11/04/10 22:18:20 INFO mapred.LocalJobRunner: reduce > reduce
11/04/10 22:18:20 INFO mapred.TaskRunner: Task 'attempt_local_0001_r_000000_0' done.
11/04/10 22:18:21 INFO mapred.JobClient:  map 100% reduce 100%
11/04/10 22:18:21 INFO mapred.JobClient: Job complete: job_local_0001
11/04/10 22:18:21 INFO mapred.JobClient: Counters: 13
11/04/10 22:18:21 INFO mapred.JobClient:   FileSystemCounters
11/04/10 22:18:21 INFO mapred.JobClient:     FILE_BYTES_READ=312116
11/04/10 22:18:21 INFO mapred.JobClient:     FILE_BYTES_WRITTEN=342151
11/04/10 22:18:21 INFO mapred.JobClient:   Map-Reduce Framework
11/04/10 22:18:21 INFO mapred.JobClient:     Reduce input groups=2
11/04/10 22:18:21 INFO mapred.JobClient:     Combine output records=0
11/04/10 22:18:21 INFO mapred.JobClient:     Map input records=1
11/04/10 22:18:21 INFO mapred.JobClient:     Reduce shuffle bytes=0
11/04/10 22:18:21 INFO mapred.JobClient:     Reduce output records=0
11/04/10 22:18:21 INFO mapred.JobClient:     Spilled Records=4
11/04/10 22:18:21 INFO mapred.JobClient:     Map output bytes=18
11/04/10 22:18:21 INFO mapred.JobClient:     Map input bytes=24
11/04/10 22:18:21 INFO mapred.JobClient:     Combine input records=0
11/04/10 22:18:21 INFO mapred.JobClient:     Map output records=2
11/04/10 22:18:21 INFO mapred.JobClient:     Reduce input records=2
Job Finished in 1.676 seconds
Estimated value of Pi is 3.14800000000000000000

うまく動いた!

疑似分散モードで動かす

${HADOOP_HOME}/confの3ファイルを編集します。

core-site.xml

?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>

<!-- Put site-specific property overrides in this file. -->

<configuration>
<property>
  <name>fs.default.name</name>
  <value>hdfs://localhost:9000</value>
</property>
</configuration>

hdfs-site.xml

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>

<!-- Put site-specific property overrides in this file. -->

<configuration>
<property>
  <name>dfs.replication</name>
  <value>1</value>
</property>
</configuration>

mapred-site.xml

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>

<!-- Put site-specific property overrides in this file. -->

<configuration>
<property>
  <name>mapred.job.tracker</name>
  <value>localhost:9001</value>
</property>
</configuration>

MapReduceで利用するHDFS領域の初期化と起動

$bin/hadoop namenode -format
$bin/start-all.sh

引数をちょっとかえて先ほどの円周率計算のサンプルプログラムの実行します。

$bin/hadoop jar hadoop-0.20.2-examples.jar pi 10 1000
Number of Maps  = 10
Samples per Map = 1000
Wrote input for Map #0
Wrote input for Map #1
Wrote input for Map #2
Wrote input for Map #3
Wrote input for Map #4
Wrote input for Map #5
Wrote input for Map #6
Wrote input for Map #7
Wrote input for Map #8
Wrote input for Map #9
Starting Job
11/04/10 22:28:10 INFO mapred.FileInputFormat: Total input paths to process : 10
11/04/10 22:28:10 INFO mapred.JobClient: Running job: job_201104102223_0002
11/04/10 22:28:11 INFO mapred.JobClient:  map 0% reduce 0%
11/04/10 22:28:19 INFO mapred.JobClient:  map 20% reduce 0%
11/04/10 22:28:22 INFO mapred.JobClient:  map 40% reduce 0%
11/04/10 22:28:25 INFO mapred.JobClient:  map 60% reduce 0%
11/04/10 22:28:28 INFO mapred.JobClient:  map 80% reduce 13%
11/04/10 22:28:31 INFO mapred.JobClient:  map 100% reduce 13%
11/04/10 22:28:40 INFO mapred.JobClient:  map 100% reduce 100%
11/04/10 22:28:42 INFO mapred.JobClient: Job complete: job_201104102223_0002
11/04/10 22:28:42 INFO mapred.JobClient: Counters: 18
11/04/10 22:28:42 INFO mapred.JobClient:   Job Counters
11/04/10 22:28:42 INFO mapred.JobClient:     Launched reduce tasks=1
11/04/10 22:28:42 INFO mapred.JobClient:     Launched map tasks=10
11/04/10 22:28:42 INFO mapred.JobClient:     Data-local map tasks=10
11/04/10 22:28:42 INFO mapred.JobClient:   FileSystemCounters
11/04/10 22:28:42 INFO mapred.JobClient:     FILE_BYTES_READ=226
11/04/10 22:28:42 INFO mapred.JobClient:     HDFS_BYTES_READ=1180
11/04/10 22:28:42 INFO mapred.JobClient:     FILE_BYTES_WRITTEN=826
11/04/10 22:28:42 INFO mapred.JobClient:     HDFS_BYTES_WRITTEN=215
11/04/10 22:28:42 INFO mapred.JobClient:   Map-Reduce Framework
11/04/10 22:28:42 INFO mapred.JobClient:     Reduce input groups=20
11/04/10 22:28:42 INFO mapred.JobClient:     Combine output records=0
11/04/10 22:28:42 INFO mapred.JobClient:     Map input records=10
11/04/10 22:28:42 INFO mapred.JobClient:     Reduce shuffle bytes=252
11/04/10 22:28:42 INFO mapred.JobClient:     Reduce output records=0
11/04/10 22:28:42 INFO mapred.JobClient:     Spilled Records=40
11/04/10 22:28:42 INFO mapred.JobClient:     Map output bytes=180
11/04/10 22:28:42 INFO mapred.JobClient:     Map input bytes=240
11/04/10 22:28:42 INFO mapred.JobClient:     Combine input records=0
11/04/10 22:28:42 INFO mapred.JobClient:     Map output records=20
11/04/10 22:28:42 INFO mapred.JobClient:     Reduce input records=20
Job Finished in 32.415 seconds
Estimated value of Pi is 3.14080000000000000000

スタンドアロンモードの時と比べて、10回のMapが行われています。
単純な演算なので、MapReduceの処理のオーバーヘッドで計算時間が遅くなってるけど、これが大規模になると高速化するのか、ごくり。

最後にHadoopの終了

$bin/stop-all.sh

次は、VMを入れて完全分散モードを試すことと、MapReduceを勉強していかないとですね。