概要

ここでは完全分散モードでHadoopのNameNodeDataNodeを導入して、分散してデータを保存できるようにしてみます。ClouderaのCDH3を利用。

最低でも2台(できれば3台以上)のパソコンが必要になります。

JobTrackerとTaskTrackerの導入についてはこちら

@Date 2011/10/29
@Versions Hadoop0.20, Ubuntu10.04, CDH3

利用するPCについて

NameNode(HDFS親)はDataNodeがどういった情報を記録しているかをメモリ上に持って管理しています。CPUの性能はそれほど必要ありませんが、メモリが足りなくなるとデータを増やせなくなります。

とは言っても、細かいファイルを大量に生成したりしなければ、512MBも割り当てておけば数十TBのデータを余裕で扱えてしまうので、自宅で使う分にはその辺の安物のPCで十分だったりします。

DataNodeはHDDの容量が多ければそれだけ多くのデータが扱えるようになりますし、HDDの台数が多ければそれだけI/Oの性能が上がります。我が家では中古で安物のHDDをいくつか買ってきて数と容量を水増ししています。秋葉原の中古屋だと500GBが2500円くらいでよく置いてあります(2011年10月時点)。

TaskTrackerは通常、DataNodeと同一マシンにインストールします。性能が良ければ良いほどMapReduceの性能が上がりますが、良いマシンを揃えようとすれば当然お金がかかります。我が家にはそんなお金はないので、処理速度は諦めて台数だけ揃えることでそれっぽい雰囲気を演出しています。

我が家では、知り合いから下取りしたノートPC(Core2Duo、メモリ2GB)をNameNodeにして、後は中古で1万円で買ったマシンや、日頃仕事で使っているマシンにHDDとメモリを足してDataNodeに割り当てるなどして台数を確保しています。

秋葉原のTWOTOPとかクレバリーとかある辺りの路地を歩いていると、OSなしで1万円切っていてCore2Duoでメモリ2GB載っているマシンをたまに見かけます。そうしたマシンにHDDを足せば、DataNode+TaskTrackerとしてそこそこに動いてくれます。

Hadoopのインストールを始める前に(全PCでやること)

Hadoopを導入する前に、入れるべきものを入れたりちょっと設定をいじったりします。この作業は利用するすべてのPCに対して行っておきます。

まずは前段階として必要なものをインストール。

// とりあえずsshのインストール
$ sudo apt-get install ssh

// 礼儀としてntpも入れる
$ sudo apt-get install ntp

// rsyncも確か必要だった気がする
$ sudo apt-get install rsync

// 都合によりcurlも入れる
$ sudo apt-get install curl

// 関係ないけど好みによりvimとか入れたり
$ sudo apt-get install vim

次にJavaのインストール。OpenJDKでも動くらしいけど、せっかくなので推奨されてるSunのを入れる。

// レポジトリの登録
$ sudo aptitude install python-software-properties
// 本例はUbuntu10.04なのでlucid partner
$ sudo add-apt-repository 'deb http://archive.canonical.com/ lucid partner'
$ sudo apt-get update

// インストール
$ sudo apt-get install sun-java6-jdk

あとは/etc/hostsを編集しておく。ここが意外とハマりどころ。

// /etc/hostsの編集
$ sudo vi /etc/hosts

hostsは最初、こんな風になっていると思われる(IPv6周りの表記は省略。「tora」はうちのNameNode用のパソコンの名前)。

127.0.0.1       localhost
127.0.1.1       tora

ここで自身の名前(この場合はtora)が127.0.x.xを指しているとNameNodeを立ち上げた時によろしくないので、以下のように、192.168.x.xの形式で自身のアドレスを含めてHadoopに含める予定のマシンを書き込んでおく。

127.0.0.1       localhost

192.168.1.31    yagi
192.168.1.33	tora
192.168.1.34	usagi
192.168.1.35	sika

NameNodeのインストール(親機のみ)

次に親になるマシン1台にNameNodeをインストールします。あとでJobTrackerも同じ機体で動かす予定なので、ついでに一緒に入れてしまいます。

// source.list.d配下にファイルを追加
$ sudo vi /etc/apt/sources.list.d/cloudera.list

deb http://archive.cloudera.com/debian lucid-cdh3 contrib
deb-src http://archive.cloudera.com/debian lucid-cdh3 contrib

// レポジトリの更新
$ curl -s http://archive.cloudera.com/debian/archive.key | sudo apt-key add -
$ sudo apt-get update

// NameNodeとJobTrackerのインストール
$ sudo apt-get install hadoop-0.20 hadoop-0.20-namenode hadoop-0.20-jobtracker

cloudera.listにlucid-cdh3と記述していますが、これはUbuntu10.04(コードネームLucid)を利用しているためです。バージョンが変わると記述も変わるはず。

バージョンごとのコード名についてはUbuntuのWikipediaのページとかが分かりやすい気がします。

これでHadoopのNameNodeとJobTrackerがインストールされました。

NameNodeはservice hadoop-0.20-namenode start | stop | statusのような形で起動や停止が行えます。

/etc/rc[0-6].dの中にも両機能が登録されており、起動時に自動的に両サービスが立ち上がるようになっています。

またhdfsmapredという2つのユーザが登録されます。hdfsはHDFSを利用する際に、mapredはMapReduceを利用する際に使うユーザです。

DataNodeのインストール(子機のみ)

DataNodeを子として使うマシンすべてにインストールします。NameNodeと同じくapt-getで入れられます。ついでなので一緒にTaskTrackerも入れてしまいます。

// source.list.d配下にファイルを追加
$ sudo vi /etc/apt/sources.list.d/cloudera.list
deb http://archive.cloudera.com/debian lucid-cdh3 contrib
deb-src http://archive.cloudera.com/debian lucid-cdh3 contrib

// レポジトリの更新
$ curl -s http://archive.cloudera.com/debian/archive.key | sudo apt-key add -
$ sudo apt-get update

// NameNodeとJobTrackerのインストール
$ sudo apt-get install hadoop-0.20 hadoop-0.20-datanode hadoop-0.20-tasktracker

これでDataNodeとTaskTrackerがインストールされます。

service hadoop-0.20-datanode start | stop | statusなどでDataNodeの起動や終了は実行できます。

update-alternatives

NameNodeやDataNodeを立ち上げる前に、設定ファイルに必要な項目を記述する必要があります。

CDH3では設定ファイルはupdate-alternativesを使って切り替えます。update-alternativesはシンボリックリンクを動的に変更できるようなシロモノです。RHEL系ではalternativesという名前になっています。

設定ファイルのあるディレクトリを切り替えることで、複数の設定(例えばローカルモードと分散モード)を手軽に使い分けられるようになります。

試しに現在の状態を表示してみます。confの設定はhadoop-0.20-confという名前で登録されています。

$ update-alternatives --display hadoop-0.20-conf
hadoop-0.20-conf - auto mode
 リンクは現在 /etc/hadoop-0.20/conf.empty を指しています
/etc/hadoop-0.20/conf.empty - 優先度 10
現在の `最適' バージョンは /etc/hadoop-0.20/conf.empty です。

上記のように現在の設定は「/etc/hadoop-0.20/conf.empty」というディレクトリに向けられているようです。これを独自のディレクトリに向くようにします。

// てきとーな名前でconf.emptyディレクトリをコピー
$ sudo cp -r /etc/hadoop-0.20/conf.empty /etc/hadoop-0.20/conf.my

// 作ったディレクトリをinstall
$ sudo update-alternatives --install /etc/hadoop-0.20/conf hadoop-0.20-conf /etc/hadoop-0.20/conf.my 50

--install後に続いている引数は、リンク先のディレクトリ、名称、リンク元のディレクトリ、優先度になります。数字が大きい方が優先度が高くなります。

conf.emptyの優先度は10だったので、50でinstallすれば今回追加した方が優先度が高くなります。

$ update-alternatives --display hadoop-0.20-conf
hadoop-0.20-conf - auto mode
 リンクは現在 /etc/hadoop-0.20/conf.my を指しています
/etc/hadoop-0.20/conf.empty - 優先度 10
/etc/hadoop-0.20/conf.my - 優先度 50
現在の `最適' バージョンは /etc/hadoop-0.20/conf.my です。

上記のようにリンクがconf.myの方を指すようになりました。

切り替える際は、$ update-alternatives --config hadoop-0.20-confを実行して、表示された中から切り替えたい設定を選択します。

hadoop-env.shの編集

先ほど作ったconf.myディレクトリの中を編集して、分散環境で動くように設定ファイルを書き換えていきます。手始めにhadoop-env.shから。

hadoop-env.shはJAVA_HOMEとかJVMのヒープサイズとかが指定できます。

$ sudo vi /etc/hadoop-0.20/conf.my/hadoop-env.sh

// こんな感じでコメントアウトしてHEAPSIZEが記述してある
// デフォルトは1000なので家庭で使う分にはそのままで問題ないと思われる
# export HADOOP_HEAPSIZE=2000

// Ubuntuの場合デフォルトではNameNodeやJobTrackerがIPv6で待ち受けるようになる
// 以下の設定を記述しておくとIPv4で受け付けるようになる
export HADOOP_OPTS=-Djava.net.preferIPv4Stack=true

NameNodeやJobTrackerはそれぞれHADOOP_HEAPSIZEで指定したサイズのメモリを使用します。

ヒープサイズはとりあえずそのままで良いとして、preferIPv4Stackの設定は書き足しておきます。

mastersとslavesの編集

次にmastersとslavesというファイルを編集します。これは単純にマスターとスレーブのマシンのホスト名を書くだけのファイルです。

$ sudo vi /etc/hadoop-0.20/conf.my/masters
tora

$ sudo vi /etc/hadoop-0.20/conf.my/slaves
yagi
usagi
sika

上記のように、NameNodeになるマシンの名前をmastersに、DataNodeになる子の名前をslavesに記述します。

core-site.xmlの編集

今回はcore-site.xmlに、fs.default.nameとhadoop.tmp.dirの2つを指定します。

$ sudo vi /etc/hadoop-0.20/conf.my/core-site.xml

<configuration>
  <property>
    <name>fs.default.name</name>
    <value>hdfs://tora:54310</value>
  </property>

  <property>
    <name>hadoop.tmp.dir</name>
    <value>/mnt/hdfs1/hadoop.tmp</value>
  </property>
</configuration>

fs.default.nameはNameNodeのサーバ名とポートを指定します。我が家のNameNodeのマシンがtoraという名前なので上記のように指定しています。

DataNodeはfs.default.nameの設定を見てNameNodeと通信します。ここで指定したサーバ名:ポート名で見に行ってNameNodeに接続できないと、DataNodeはエラーを吐きます。

hadoop.tmp.dirはhadoop関連のファイルが置かれる場所を指定します。

NameNodeの情報やDataNodeで保存されるデータは、デフォルトではhadoop.tmp.dirの配下に出力されます。いろんなファイルが出力されることになるので、valueにはいろいろファイルが出力されても構わない、容量に余裕があるパスを指定しておく必要があります。

hdfs-site.xmlの編集

hdfs-site.xmlは名前の通りHDFS関連の設定を行います。

dfs.name.dirとかdfs.data.dirでNameNodeやDataNodeのデータを保存しておく場所を指定できます。今回は特に指定をせずにデフォルトのままにしておきます。

デフォルト値は前述で出たhadoop.tmp.dirの配下で、NameNodeが${hadoop.tmp.dir}/dfs/name、DataNodeが${hadoop.tmp.dir}/dfs/dataになります。

あとはdfs.replication(HDFS上のデータの複製を作る数。デフォルトは3個作る)の設定もできます。自宅で使う分には常時DataNodeを3台以上キープできるか分からないのでとりあえず2にしておきます。DataNodeを1〜2台しか利用しない場合は1を設定しておきます。

$ sudo vi /etc/hadoop-0.20/conf.my/hdfs-site.xml

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

ディレクトリの作成

HDFSの処理はhdfsユーザによって実行されます。

なのでdfs.name.dirやdfs.data.dirの対象になるディレクトリは、hdfsユーザが操作できる権限を持っている必要があります。

今回は/mnt/hdfs1/hadoopというディレクトリをhadoop.tmp.dirに設定しているので、そのディレクトリのユーザをhdfsにしてしまえばとりあえずファイルは書けるようになるはず。

$ sudo mkdir /mnt/hdfs1/hadoop.tmp
$ sudo chown hdfs:hdfs /mnt/hdfs1/hadoop.tmp

NameNodeの起動

NameNodeを起動する前に、前述までに生成した設定(conf.myディレクトリ)をすべてのNameNodeとDataNodeに配置します。また、update-alternativesで配置したディレクトリが優先的に見られるよう指定します。

設定の共有は面倒なので個人的にはNameNodeに置いた設定をNFSで子供から見れるようにしています。

準備ができたらNameNodeをインストールしたマシンでNameNodeの初期化を行ないます。実行はhdfsユーザで行う必要があります。

$ sudo -u hdfs hadoop namenode -format

次にNameNodeを起動します。

// とりあえず起動しているか確認
$ service hadoop-0.20-namenode status

// not runningならstartを、runningならrestartする
$ sudo service hadoop-0.20-namenode start

起動したら以下のURL(toraの部分はNameNodeのhost名に変更すること)で状態を見てみる。
http://tora:50070/

まだDataNodeが立ち上がっていないので、ほとんどの数字が0KBの状態になっていると思います。

うまく起動できなかった場合は以下のログを見ます。

Log : /usr/lib/hadoop-0.20/logs/hadoop-hadoop-namenode-*.log

たいていの問題は上記のログのエラー部分をググると解決できます。

DataNodeの起動

次に手近なマシンのDataNodeを起動します。

$ sudo service hadoop-0.20-datanode start

うまく起動すれば、以下のURL(toraの部分はNameNodeのhost名に変更すること)の数字に変化が出ます。

http://tora:50070/

起動が成功していれば、これまで0KBだったConfigured Capacityなどの項目に、今回立ち上げたDataNodeの分だけ領域が加算されます(反映されるまでは数十秒かかる場合があります)。

0KBのままだった場合は起動に失敗しているので、とりあえずログを見ます。

$ vi /usr/lib/hadoop-0.20/logs/hadoop-hadoop-datanode-*.log

エラー原因は、DataNode用のディレクトリが権限不足で作れないか(実は親ディレクトリが700になってるとか)、NameNodeへの通信が確立できないケースなんかによく出くわします。

接続が確立できない場合はFirewallとかhostsの設定とかいろいろ原因が考えられます。とりあえず最低限telnetコマンドが通る状態である必要はあります。

$ telnet tora 54310

また、NameNode側のマシンでnetstatして、ちゃんと指定のポート(core-site.xmlのfs.default.nameで指定した)で待ち受けているかも確認しておきます。

$ netstat -p tcp

うまく立ち上がったら残りのDataNodeも立ち上げます。立ち上げるたびに、http://tora:50070/のページのLive Nodesの項の数値が増えていきます。3匹立ち上げれば3、5匹立ち上げれば5と表示されるはずです。

DFS Remainingのところが、残りの容量です。台数を増やせば10TBを超えるようなサイズのファイルでも扱えるようになります。

HDDを複数台載っている場合

上記の設定では複数HDDを載せているマシンでも1つのHDDしか使用されない設定になっています。

複数のHDDを載せている場合は、hdfs-site.xmlのdfs.data.dirにカンマ区切りで他のHDDがマウントされているパスを書く必要があります。

$ sudo vi /etc/hadoop-0.20/conf.my/hdfs-site.xml

  <property>
    <name>dfs.data.dir</name>
    <value>/mnt/hdfs1/hadoop.tmp,/mnt/hdfs2/hadoop.tmp,/mnt/hdfs3/hadoop.tmp</value>
  </property>

設定後、対象のディレクトリを作成します。

$ sudo mkdir /mnt/hdd2/hadoop.tmp
$ sudo mkdir /mnt/hdd3/hadoop.tmp

$ sudo chown hdfs:hdfs /mnt/hdd2/hadoop.tmp
$ sudo chown hdfs:hdfs /mnt/hdd3/hadoop.tmp

設定を読み込ませるためにDataNodeを再起動します。

$ sudo service hadoop-0.20-datanode restart

これで3つのHDDが使用されるようになりました。http://tora:50070/のLive Nodesのリンクをクリックすると、各マシンごとの容量を見ることができます。ここで出ている値が指定したHDDの容量の合算になっていれば成功です。