1. 前回のおさらい
前回はGoogleの基盤技術とそれに対応するオープンソースソフトウェアとして、Hadoop & hBaseを紹介しました(図1 参照)。今回はHadoopを1台にインストールし、サンプルプログラムを動かします。次にHDFSとMapReduceのアーキテクチャを解説します。最後にサンプルプログラムのソースコードを解説します。
2. Hadoopの概要
Hadoopは主にYahoo! Inc.のDoug Cutting氏によって開発が進められているオープンソースソフトウェアで、GoogleFileSystemとMapReduceというGoogleの基盤技術のオープンソース実装です。Hadoopという名前は開発者の子供が持っている黄色い象のぬいぐるみの名前に由来しています。HadoopはHDFS(Hadoop Distributed File System)、Hadoop MapReduce Frameworkから構成されています。
HDFSは大規模なファイルを効率的に、また安全に扱うことに特化した分散ファイルシステムです。Googleの基盤技術で言うとGFSに対応するものです。Hadoop MapReduce FrameworkはHDFSの上で分散計算を行うためのフレームワークです。大規模なデータをHDFSから読み込み、MapというフェーズとReduceというフェーズで並列処理をした後、計算結果をHDFSに保存します。
HadoopはJavaで記述されており、MapReduceプログラムを書く場合も基本的にはJavaで記述することが想定されています。ただしHadoop Streamingという拡張パッケージを用いると、C/C++・Ruby・Pythonなど任意の言語で標準入出力を介したMapReduceプログラムを書くこともできます。
今回はまず1台にHadoopをインストールし、サンプルプログラムを動かしてみます。次にHDFSのアーキテクチャの説明とMapReduceの解説を行います。複数台での動作方法については第3回で触れていきたいと思います。
3. Hadoopのインストール
3.1 準備
今回の記事ではRHEL5(Linux Kernel 2.6.18 SMP, x86 64)の環境を用います。あらかじめJava SE Development Kit(JDK、v1.6以上推奨)をインストールしておく必要があります。記事ではJDK v1.6.0 06を使用しました。
最近のシステムにはgcjが入っている事が多いのですが、Sun純正のJava VMがデフォルトで使われるようにしておいてください。Ubuntu Linuxの場合は「/etc/jvm」を書き換えるなどの作業が必要なようです。
次にsshの設定をして、localhostにノーパスワードで入れるようにしておきます(図2)。パスフレーズ付きの鍵を使用している場合は新しく鍵を生成するなどして下さい(図3)。
[kzk@mizugaki0 ~]$ ssh localhost Last login: Mon Apr 21 18:52:58 2008 from localhost.localdomain [kzk@mizugaki0 ~]$
[kzk@mizugaki0 ~]$ ssh-keygen -t rsa -P "" [kzk@mizugaki0 ~]$ cat .ssh/id_rsa.pub >> .ssh/authorized_keys
3.2 Hadoop本体のダウンロード
Hadoopのダウンロードページから「hadoop-[VERSION].tar.gz」をダウンロードしてきます。今回は記事執筆時点での安定版であるversion 0.15.3を使用しました。0.16.4が最新版のリリースなのですが、クラスタで使用してみたところ各ノードの仕事量が一定しないなどの問題点がありましたので、今回の記事では安定版を使います。これをホーム直下の「hadoop」というディレクトリに解凍します(図4)。以降、このディレクトリを[HADOOP INSTALL]という記法で表します。
[kzk@mizugaki0 ~]$ tar zxf hadoop-0.15.3.tar.gz [kzk@mizugaki0 ~]$ mv hadoop-0.15.3 hadoop
3.3 hadoop-env.sh の編集
[HADOOP INSTALL]/conf/hadoop-env.sh を編集し、JAVA_HOME
環境変数を適切に設定します。またこれは必須では無いですが、大量のデータを扱うためにHADOOP_HEAPSIZE
をデフォルトの1000Mから増やしておくのが良いでしょう。
3.4 hadoop-site.xml の編集
[HADOOP INSTALL]/conf/hadoop-default.xml を [HADOOP INSTALL]/conf/hadoop-site.xml にコピーします。Hadoop全体の設定に関してはこの hadoop-site.xml を編集することになります。さらに図5に示した4つの設定を編集します。hadoop.tmp.dir については各自適切な値を設定してください。
<property> <name>hadoop.tmp.dir</name> <value>/path/to/hadoop/tmp/dir</value> </property> <property> <name>fs.default.name</name> <value>hdfs://localhost:54310</value> </property> <property> <name>mapred.job.tracker</name> <value>localhost:54311</value> </property> <property> <name>dfs.replication</name> <value>1</value> </property>
54310, 54311というポート番号は適当に選択しています。
他の設定値についてはこのページを参考にして下さい。マルチコアCPUを使用している場合は、mapred.tasktracker.tasks.maximum
とmapred.tasktracker.reduce.tasks.maximum
を1以上の値にすると良いでしょう。実験してみたところによると、大体CPU数 +1 か +2 ぐらいの値を設定すると良いようです。
3.5 フォーマット & 起動 & 終了
初回起動時だけHadoopに必要なデータのフォーマットを行う必要があります。これを行った後、「bin/start-all.sh」というスクリプトで起動できます。終了するには「bin/stop-all.sh」というスクリプトを使用します。起動しているかどうかはjpsというコマンドで確認できます(図6)。
[kzk@mizugaki0 ~]$ cd hadoop [kzk@mizugaki0 hadoop]$ ./bin/hadoop namenode -format # フォーマット [kzk@mizugaki0 hadoop]$ ./bin/start-all.sh # 起動 [kzk@mizugaki0 hadoop]$ jps # 起動確認 32394 TaskTracker 32263 JobTracker 31912 NameNode 32034 DataNode 32474 Jps 32185 SecondaryNameNode [kzk@mizugaki0 hadoop]$ ./bin/stop-all.sh # 終了
3.6 サンプルプログラムを動かす
それでは実際にHadoopを使用してみます。配布物には、文章中の単語出現数をカウントするMapReduceプログラムが含まれていますので、これを動かしてみます。
MapReduceプログラムは入力としてHDFS上のファイルを使用します。そのため、まずはローカルにある「inputs」というディレクトリを丸ごとHDFS上に転送する必要があります(図7)。これには bin/hadoop dfs -copyFromLocal(もしくは -put)というコマンドを用います。GFSではこの操作を行う際にファンシーな表示がされるようです。
[kzk@mizugaki0 hadoop]$ mkdir inputs # ディレクトリ作成 [kzk@mizugaki0 hadoop]$ cat > inputs/file1 # サンプルファイルを用意 hoge hoge hoge fuga fuga [kzk@mizugaki0 hadoop]$ bin/hadoop dfs -copyFromLocal inputs inputs # HDFS に転送 [kzk@mizugaki0 hadoop]$ bin/hadoop dfs -ls Found 1 items /user/kzk/inputs <dir> 2008-04-21 20:23 rwxr-xr-x kzk supergroup [kzk@mizugaki0 hadoop]$ bin/hadoop dfs -ls inputs Found 1 items /user/kzk/inputs/file1 <r 1> 25 2008-04-21 20:23 rw-r--r-- kzk supergroup
NFSのようにUNIXからシームレスに使用できる分散ファイルシステムを想像されていた方には少し奇怪に見えるかもしれませんが、HDFSは標準添付されている cp や rm といったコマンドではアクセスできません。代わりに bin/hadoop dfs コマンドですべてのファイル操作を行います。
次にこのファイルを入力に指定してMapReduceプログラムを起動します(図8)。このプログラムは、入力に指定されたディレクトリ以下のファイルについて、出現するすべてのワードとその出現回数をカウントするプログラムです。
[kzk@mizugaki0 hadoop]$ ./bin/hadoop jar hadoop-0.15.3-examples.jar wordcount inputs outputs 08/04/21 20:24:30 INFO mapred.FileInputFormat: Total input pathsr to process : 1 08/04/21 20:24:30 INFO mapred.JobClient: Running job: job_200804212009_0001 08/04/21 20:24:31 INFO mapred.JobClient: map 0% reduce 0% 08/04/21 20:24:35 INFO mapred.JobClient: map 100% reduce 0% 08/04/21 20:24:43 INFO mapred.JobClient: map 100% reduce 100% 08/04/21 20:24:44 INFO mapred.JobClient: Job complete: job_200804212009_0001 08/04/21 20:24:45 INFO mapred.JobClient: Counters: 12 08/04/21 20:24:45 INFO mapred.JobClient: Job Counters 08/04/21 20:24:45 INFO mapred.JobClient: Launched map tasks=2 08/04/21 20:24:45 INFO mapred.JobClient: Launched reduce tasks=1 08/04/21 20:24:45 INFO mapred.JobClient: Data-local map tasks=2 08/04/21 20:24:45 INFO mapred.JobClient: Map-Reduce Framework 08/04/21 20:24:45 INFO mapred.JobClient: Map input records=1 08/04/21 20:24:45 INFO mapred.JobClient: Map output records=5 08/04/21 20:24:45 INFO mapred.JobClient: Map input bytes=25 08/04/21 20:24:45 INFO mapred.JobClient: Map output bytes=45 08/04/21 20:24:45 INFO mapred.JobClient: Combine input records=5 08/04/21 20:24:45 INFO mapred.JobClient: Combine output records=2 08/04/21 20:24:45 INFO mapred.JobClient: Reduce input groups=2 08/04/21 20:24:45 INFO mapred.JobClient: Reduce input records=2 08/04/21 20:24:45 INFO mapred.JobClient: Reduce output records=2
最後にHDFS上に保存された出力ファイルを確認します(図9)。dfs -cat でHDFS上のファイルをそのまま出力させることもできますし、-copyToLocal もしくは -get でファイルをHDFSから手元にダウンロードできます。
[kzk@mizugaki0 hadoop]$ bin/hadoop dfs -ls Found 2 items /user/kzk/inputs <dir> 2008-04-21 20:23 rwxr-xr-x kzk supergroup /user/kzk/outputs <dir> 2008-04-21 20:24 rwxr-xr-x kzk supergroup [kzk@mizugaki0 hadoop]$ bin/hadoop dfs -ls outputs Found 1 items /user/kzk/outputs/part-00000 <r 1> 14 2008-04-21 20:24 rw-r--r-- kzk supergroup [kzk@mizugaki0 hadoop]$ bin/hadoop dfs -cat outputs/part-00000 # HDFS 上のファイルを出力 fuga 2 hoge 3 [kzk@mizugaki0 hadoop]$ bin/hadoop dfs -copyToLocal outputs/part-00000 ./part-00000 # HDFS 上のファイルをローカルに転送 [kzk@mizugaki0 hadoop]$ cat part-00000 fuga 2 hoge 3
逐一 bin/hadoop dfs コマンドを実行するのが面倒な場合は、図10のように.bashrcによく使うコマンドをaliasで指定しておくと良いかと思います。
# .bashrc alias dfsls='~/hadoop/bin/hadoop dfs -ls' # ls alias dfsrm='~/hadoop/bin/hadoop dfs -rm' # rm alias dfscat='~/hadoop/bin/hadoop dfs -cat' # cat alias dfsrmr='~/hadoop/bin/hadoop dfs -rmr' # rm -r alias dfsmkdir='~/hadoop/bin/hadoop dfs -mkdir' # mkdir alias dfsput='~/hadoop/bin/hadoop dfs -put' # HDFS に転送 alias dfsget='~/hadoop/bin/hadoop dfs -get' # HDFS から転送
試された方は驚かれたと思いますが、たったこれだけの処理に約15秒ほどかかります。非常に遅いと思われるかもしれませんが、Hadoopは大規模なデータ処理に特化していることを思い出してください。
このような小さいファイルを処理する際には、サーバー間通信・プログラム起動などのオーバーヘッドの方が大きくなります。逆に、数時間~数日動かすような重い処理の場合には威力を発揮します。複数台へのインストール方法とベンチマーク結果などについては次回に取り組んでみたいと思います。
次章からはHadoopの中身を解説していきます。