S-JIS[2011-11-03] 変更履歴

Hadoop(仮想)分散環境作成 試行錯誤

VMware Player上の仮想マシンを使ってHadoop完全分散環境を構築した際の経過。


CentOSへのインストール

CDH3版Hadoop本体がCentOSへインストールされている前提で、そのCentOSをNameNodeとし、VMイメージをコピーしてDataNodeを作る。[2011-09-25]

  1. VMware上のCentOSを起動し、rootユーザーでログインする。
  2. NameNodeやDataNode用のデーモンを起動する為のシェルをインストールする。
    # yum install -y hadoop-0.20-namenode
    # yum install -y hadoop-0.20-datanode
    # yum install -y hadoop-0.20-secondarynamenode
    # yum install -y hadoop-0.20-jobtracker
    # yum install -y hadoop-0.20-tasktracker
  3. 新しいコンフィグレーションを作成する。
    1. 単独環境用のconf.emptyをコピーして分散環境用のconfを作る。
      # cd /etc/hadoop-0.20
      # cp -rp conf.empty conf.cluster
      # cd conf.cluster
    2. conf.clusterをalternativesに登録する。
      # alternatives --install /etc/hadoop-0.20/conf hadoop-0.20-conf /etc/hadoop-0.20/conf.cluster 50
      # alternatives --display hadoop-0.20-conf
    3. 自分のIPアドレスを確認する。(デフォルトでは、VMwareのDHCP機能で自動的にIPアドレスが割り当てられているから)
      # ifconfig
    4. /etc/hostsファイルに自分のホスト名を設定しておく。
      192.168.129.2   namenode.hadoop.hishidama.jp namenode
    5. conf.clusterの下の設定ファイルを編集する。
      ファイル名 設定例 備考
      core-site.xml
      <property>
      <name>fs.default.name</name>
      <value>hdfs://namenode:50010</value>
      </property>
       
      <property>
      <name>hadoop.tmp.dir</name>
      <value>/var/lib/hadoop-0.20/cache/${user.name}</value>
      </property>
       
      hdfs-site.xml
      <property>
      <name>dfs.replication</name>
      <value>2</value>
      </property>
      レプリケーション(データの複製)数の指定。
      <property>
      <name>dfs.permissions</name>
      <value>false</value>
      </property>
      HDFSへアクセスできる権限制限の有無。
      true(デフォルト)にしておくと、
      書込権限の無いディレクトリーへファイルをputしようとしたときに
      org.apache.hadoop.security.AccessControlException: Permission denied」が発生する。
      <property>
      <name>dfs.http.address</name>
      <value>namenode:50070</value>
      </property>
       
      <property>
      <name>dfs.name.dir</name>
      <value>/var/lib/hadoop-0.20/cache/hadoop/dfs/name</value>
      </property>
       
      mapred-site.xml
      <property>
      <name>mapred.job.tracker</name>
      <value>namenode:50011</value>
      </property>
       
    6. NameNodeをフォーマットする。
      # mkdir -p /var/lib/hadoop-0.20/cache
      # chmod -R 1777 /var/lib/hadoop-0.20
      # su - hdfs
      $ hadoop namenode -format
      $ exit
    7. ファイヤーウォールを無効にしておく。
      1. CentOSのGUIの上部のメニューの「システム」→「管理」→「セキュリティレベルとファイヤーウォールの設定」で「セキュリティレベルの設定」ダイアログを開く。
      2. 「ファイアウォール」で「無効」を選択する。
  4. VMware上のCentOSを一旦シャットダウンする。
  5. インストールしたCentOSのVMwareイメージのディレクトリーをコピーして、DataNode用とする。
    コピーしたディレクトリー内の拡張子「.vmx」のファイルをテキストエディターで開き、displayNameを変えておくと、後から分かりやすい。(VMware Playerを起動したときの一覧に表示される)
  6. DataNode用VMイメージの拡張子「.vmx」のファイルを実行する。
    「この仮想マシンは移動またはコピーされた可能性があります」と表示されたら、「コピーしました」を選択する。
  7. NameNode用の仮想マシンを実行し、NameNodeを起動する。
    # /etc/init.d/hadoop-0.20-namenode start
    # /etc/init.d/hadoop-0.20-jobtracker start
  8. DataNodeを起動する。各データノードで以下のコマンドを実行する。
    # /etc/init.d/hadoop-0.20-datanode start
    # /etc/init.d/hadoop-0.20-tasktracker start

Hadoopの各デーモンが起動しているかどうかは、以下のコマンドで確認できる。

# /etc/init.d/hadoop-0.20-namenode status
# /etc/init.d/hadoop-0.20-jobtracker status
# /etc/init.d/hadoop-0.20-datanode status
# /etc/init.d/hadoop-0.20-tasktracker status
# service --status-all | grep node
# service --status-all | grep tracker

Too many fetch-failures エラー

環境が出来たので、試しに円周率を計算するサンプルを動かしてみる。[2011-11-03]

NameNodeからhdfsユーザーで以下のコマンドを実行する。

$ hadoop jar /usr/lib/hadoop/hadoop-*-examples.jar pi 4 2000
Number of Maps = 4
Samples per Map = 2000
Wrote input for Map #0
Wrote input for Map #1
Wrote input for Map #2
Wrote input for Map #3
Starting Job
11/11/03 09:46:25 INFO mapred.FileInputFormat: Total input paths to process : 4
11/11/03 09:46:25 INFO mapred.JobClient: Running job: job_201111010257_0007
11/11/03 09:46:26 INFO mapred.JobClient: map 0% reduce 0%
11/11/03 09:46:33 INFO mapred.JobClient: map 75% reduce 0%
11/11/03 09:46:34 INFO mapred.JobClient: map 100% reduce 0%
11/11/03 09:46:46 INFO mapred.JobClient: map 100% reduce 16%	↓ここでエラー発生
11/11/03 09:47:21 INFO mapred.JobClient: Task Id : attempt_201111010257_0007_m_000002_0, Status : FAILED
Too many fetch-failures
11/11/03 09:47:21 WARN mapred.JobClient: Error reading task outputConnection refused
11/11/03 09:47:21 WARN mapred.JobClient: Error reading task outputConnection refused
11/11/03 09:47:23 INFO mapred.JobClient: map 75% reduce 16%	←Mapタスクの一部をやり直し
11/11/03 09:47:24 INFO mapred.JobClient: map 100% reduce 16%	←ここで一分ほど停止
11/11/03 09:48:44 INFO mapred.JobClient: map 100% reduce 33%
11/11/03 09:48:46 INFO mapred.JobClient: map 100% reduce 100%
11/11/03 09:48:47 INFO mapred.JobClient: Job complete: job_201111010257_0007
〜
Job Finished in 142.127 seconds
Estimated value of Pi is 3.14100000000000000000

途中までは順調に動いたのだが、Reduceフェーズに入ったところで「Too many fetch-failures」というエラーが出て、実行が遅くなった。(止まっているようにしか見えない)
運が良ければ遅いながらも正常終了するのだが、運が悪いとずっと止まったまんま…。

ブラウザーからNameNodeのポート50030にアクセスするとジョブの一覧が見られるので
このジョブを確認してみると、Mapタスクの一部が「Too many fetch-failures」というエラーで失敗し、再実行して成功している。
このとき、タスクを実行しているマシンの名前が「/default-rack/localhost.localdomain」になっているのが気になるところ。「localhost」って…?

「Too many fetch-failures」でネットを検索してみると、yoshitsuguさんのページが出てくる。
基本的にはネットワークの設定(ノード間の通信が出来ること)を確認せよという事らしい。

結論から言うと、当初の環境設定ではデータノードに対してホスト名の設定をしていなかったのがいけなかったようだorz


データノードのホスト名の変更

NameNodeが正常に稼動すれば、ブラウザーからNameNodeのポート50070にアクセスすると、Hadoopクラスター(HDFS)の状態が確認できる。[2011-11-03]

http://namenode:50070
http://namenode:50070/dfshealth.jsp

項目 説明
Live Nodes 稼動しているデータノードの個数。
Dead Nodes 落ちているデータノードの個数。

「Live Nodes」をクリックすると、稼動しているデータノードの一覧が表示される。
で、ここで表示されるデータノードの名前が全部「localhost」になっていた(苦笑)
(ちなみに、このホスト名部分はリンクになっており、aタグのtitle属性にIPアドレスが設定されているので、ブラウザーによってはリンク上にマウスを置くとポップアップでIPアドレスが表示される。このIPアドレスは正しかった)

データノードで自身のホスト名を設定しない場合、デフォルトの「localhost.localdomain」になっている。
そこで、データノードのホスト名を設定してやる。

  1. 各データノードの/etc/sysconfig/networkに(そのデータノード自身の)ホスト名を記述する。
    (デフォルトが「localhost.localdomain」なので、自分が付けたい名前に変更する)
    NETWORKING=yes
    NETWORKING_IPV6=yes
    #HOSTNAME=localhost.localdomain
    HOSTNAME=datanode01.hadoop.hishidama.jp
  2. ネームノードおよび各データノードの/etc/hostsにデータノード全てのホスト名を追加する。
    192.168.129.2   namenode.hadoop.hishidama.jp namenode
    192.168.129.3   datanode01.hadoop.hishidama.jp
    192.168.129.4   datanode02.hadoop.hishidama.jp
    192.168.129.5   datanode03.hadoop.hishidama.jp
  3. 各データノードのネットワークを再起動する。(ホスト名が反映されれば、hostnameコマンドでそれが表示されるはず)
    # /etc/init.d/network restart
    # hostname
  4. 各データノードのDataNode・TaskTrackerを再起動する。
    # /etc/init.d/hadoop-0.20-datanode restart
    # /etc/init.d/hadoop-0.20-tasktracker restart

本来、/etc/hostsは固定IPに対してホスト名を書いておくものであり、今回の環境は動的IP(VMwareによるDHCP)なのだが、
DHCPでも(頻繁に使う場合は)割り当てられたIPアドレスが変わることはまず無いので、hostsに書く方法にした。(この方が分かりやすいから )

なお、/etc/sysconfig/networkを書き換えなくても、/etc/hostsだけ書けばホスト名は変わるっぽい。


データノードの/etc/hostsに自分自身のホスト名を追加しているのは、自分のホスト名が解決できないと(「ping 自分のホスト名」がエラーになる状態だと)データノード起動時にエラーになる為。

# /etc/init.d/hadoop-0.20-datanode start
Starting Hadoop datanode daemon (hadoop-datanode): starting datanode, logging to /usr/lib/hadoop-0.20/logs/hadoop-hadoop-datanode-datanode01.hadoop.hishidama.jp.out
                                                           [ OK ]
datanode が停止していますが PID ファイルが残っています

/usr/lib/hadoop-0.20/logs/hadoop-hadoop-datanode-datanode01.hadoop.hishidama.jp.log:
あるいは /var/log/hadoop/hadoop-hadoop-datanode-datanode01.hadoop.hishidama.jp.log:

2011-11-03 10:23:17,375 INFO org.apache.hadoop.metrics.MetricsUtil: Unable to obtain hostName
java.net.UnknownHostException: datanode01.hadoop.hishidama.jp: datanode01.hadoop.hishidama.jp
	at java.net.InetAddress.getLocalHost(InetAddress.java:1360)
	〜
2011-11-03 10:23:17,863 ERROR org.apache.hadoop.hdfs.server.datanode.DataNode: java.net.UnknownHostException: datanode01.hadoop.hishidama.jp: datanode01.hadoop.hishidama.jp
	at java.net.InetAddress.getLocalHost(InetAddress.java:1360)
	〜
2011-11-03 10:23:17,864 INFO org.apache.hadoop.hdfs.server.datanode.DataNode: SHUTDOWN_MSG:
/************************************************************
SHUTDOWN_MSG: Shutting down DataNode at java.net.UnknownHostException: datanode01.hadoop.hishidama.jp: datanode01.hadoop.hishidama.jp
************************************************************/

ネームノードがデータノードにアクセスする際もデータノードのホスト名を使うので、
ネームノードの/etc/hostsには全てのデータノードのホスト名を書いておく必要がある。

タスク実行中にデータノードが他のデータノードにアクセスする事もあるので、
データノードの/etc/hostsにも全てのデータノードのホスト名が書いてある必要がある。


分散環境構築手順へ戻る / Hadoop目次へ戻る / 技術メモへ戻る
メールの送信先:ひしだま