RSS2.0

Hadoop を Pseudo-Distributed Mode で試してみた

大量データの分析で威力を発揮するものの、癖が強すぎて適応分野の選定が難しいと一部で話題になっているらしい Hadoop ですが、これまでなかなか触る機会がなかったため、少し触ってみることにしました。実際にうまく使いこなせている人達は企業でさえも 10 〜 20 社あるかないかとか言われてるらしいですが、個人的に何も知見がないため、何を言われていても「へ〜そうなんだ〜」と返すしかありません。エンジニアとしてそんな状況もどうなんだと思ったので、ちょっと遊んでみることにしました。

ちなみに、Hadoop には大きく分けて Standalone Mode、Pseudo-Distributed Mode、Fully-Distributed Mode の 3 つの構築方法があるそうで、公式ドキュメントちょっと遊んでみるなら単一ノード構成がいいよと書かれていたので Pseudo-Distributed Mode で遊んでみることにしました。ざっとドキュメントを読んだ感じ、Standalone Mode は分析用のロジックを動かしてみるだけで、Hadoop の特徴らしい HDFS なんかにまったく触らず終わりそうだったので、やめておきます。分析ロジックが jar なので、自分で書いた jar を試しに動かしてみるには Standalone Mode が良さそうです。

なお、今回はらしいらしいという記述が多くなっていますが、分散処理は奥が深そうで、現時点では断言できることが少ないためです。ブログにはなるべくしっかりとした情報を書きたいのですが、これに関しては仕方ないかなと思います。ご了承ください。

Hadoop を Pseudo-Distributed Mode で構築する

公式ドキュメントを参考に、例によって Linux 環境で構築していきます。

hadoop ユーザーを作成する

ユーザーは誰でもいいですが、ここでは Hadoop 専用ユーザーを作っておきます。
# useradd hadoop
# passwd hadoop
移行はこの hadoop ユーザーで作業をしていきます。

必要なソフトウェアを用意する

以下の 3 つが必要になります。

Java 7 以上

環境変数 JAVA_HOME を設定し、コマンドラインから java が使えるようにパスを通しておきます。

sshd

Hadoop が ssh で通信をするので、接続先ノードには sshd を動かしておく必要があります。
普通はノードを複数並べた構成にするはずですが、今日は遊んでみるだけなので単一ノード構成になります。ということは、接続先もローカルマシンになるのでローカルで sshd を動かしておきましょう、ということですね。

ssh

単一ノード構成では接続元もローカルマシンになるので、ローカルマシンで ssh が使える必要があります。
パスワード無しで localhsot に ssh できるように設定します。
$ ssh localhost

パスワードを聞かれた場合は、聞かれなくて済むように証明書を設定しておきます。ssh 先がローカルマシンになるので、ローカルマシンに SSL 公開鍵を登録します。
$ ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa
$ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
$ chmod 0600 ~/.ssh/authorized_keys

Hadoop をインストールする

公式サイトからアーカイブをとってきます。ここではHadoop ver 2.8.0にします。
$ wget http://ftp.jaist.ac.jp/pub/apache/hadoop/common/hadoop-2.8.0/hadoop-2.8.0.tar.gz

展開して配置します。
配置先はどこでもいいですが、私は /usr/local 下に置いておくことにします。
$ tar xvfz hadoop-2.8.0.tar.gz
# mv hadoop-2.8.0 /usr/local/

bin ディレクトリ、sbin ディレクトリ下に Hadoop のコマンドがあるので、こちらを実行できるようパスを通します。
sbin ディレクトリ下のスクリプトに PATH を通すかは意見が別れるところですが、今回は面倒なので通します。
$ vi ~/.bashrc
----------------------------
...
HADOOP_HOME="/usr/local/hadoop-2.8.0"

PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin
...
----------------------------
$ source ~/.bashrc

パスを通したら動作確認をしてみます。hadoop コマンドを実行できれば OK です。
$ hadoop version
Hadoop 2.8.0
Subversion https://git-wip-us.apache.org/repos/asf/hadoop.git -r 91f2b7a13d1e97be65db92ddabc627cc29ac0009
Compiled by jdu on 2017-03-17T04:12Z
Compiled with protoc 2.5.0
From source with checksum 60125541c2b3e266cbf3becc5bda666
This command was run using /usr/local/hadoop-2.8.0/share/hadoop/common/hadoop-common-2.8.0.jar

Pseudo-Distributed Mode で動かす

Hadoop を Pseudo-Distributed Mode で動かすために設定ファイルを編集します。
Hadoop のインストールディレクトリ下の各ファイルを以下のように修正します。

etc/hadoop/core-site.xml を設定する

ファイルシステムに HDFS を利用します。
HDFS は Hadoop Distributed File System の略で、Hadoop での分散処理用に設計されたものらしいです。1 つのファイルを複数に分割してディスクに配置することで、I/O 性能を上げる等の工夫がされているそうです。
<configuration>
  <property>
    <name>fs.defaultFS</name>
    <value>hdfs://localhost:9000</value>
  </property>

  <!-- 一時ファイルのファイル置き場 -->
  <property>
    <name>hadoop.tmp.dir</name>
    <value>file:/home/hadoop/tmp</value>
  </property>
</configuration>
hadoop.tmp.dir 値には Hadoop が利用する一時ファイルの配置場所を設定します。

etc/hadoop/hdfs-site.xml を設定する

HDFS の設定を行います。

HDFS は NameNode と DataNode によって構成されます。
HDFS ではファイルはいくつかのブロックに分割されて配置されます。ブロックに分割されたファイルが実際に配置されるのが DataNode です。NameNode には実ファイルは配置されず、どのファイルがどの DataNode のどのブロックに配置されているかというメタ情報のみを扱います。NameNode はそのようなメタデータをメモリ上に展開するため、多量のメモリが必要になります。

dfs.replication 値には DataNode のレプリケーション数を指定します。今回は単一ノード構成なので 1 です。複数ノード構成では適切なレプリケーション数を指定することで、耐障害性を上げることができます。
dfs.namenode.data.dir 値には NameNode が、dfs.datanode.data.dir 値には DataNode が利用するディレクトリを設定します。
<configuration>
  <property>
    <name>dfs.replication</name>
    <value>1</value>
  </property>

  <!-- NameNode のファイル置き場 -->
  <property>
    <name>dfs.namenode.data.dir</name>
    <value>file:/home/hadoop/hdfs/namenode</value>
  </property>

  <!-- DataNode のファイル置き場 -->
  <property>
    <name>dfs.datanode.data.dir</name>
    <value>file:/home/hadoop/hdfs/datanode</value>
  </property>
</configuration>

HDFS ファイルシステムをフォーマットする

ファイルシステムをフォーマットする、と聞くと Linux パーティションがまるごとフォーマットされそうな気がしますが、その心配はありません。実際には hdfs-site.xml で設定したディレクトリに HDFS のデータが作られ、実ファイルが格納されることになります。
$ hdfs namenode -format
17/03/29 10:31:08 INFO namenode.NameNode: STARTUP_MSG: 
/************************************************************
STARTUP_MSG: Starting NameNode
STARTUP_MSG:   user = hadoop
...
17/03/29 10:31:09 INFO common.Storage: Storage directory /home/hadoop/hdfs/namenode has been successfully formatted.
...

NameNode デーモンと DataNode デーモンを起動する

HDFS を動かすため、NameNode デーモンと DataNode デーモンを起動します。ファイルシステムを動かすというのも変な感じですが、Linux ファイルシステム上で擬似的に独自のファイルシステムを再現する設計になっているため、デーモンが必要になるようです。

起動スクリプト start-dfs.sh を実行すればいいのですが、そのままでは java コマンドが探せずエラーになったので、etc/hadoop/hadoop-env.sh に JAVA_HOME を直接設定しておきます。
...
# The java implementation to use.
export JAVA_HOME=/usr/java/jre1.8.0_111
#export JAVA_HOME=${JAVA_HOME}
...

これで、start-dfs.sh を実行すれば HDFS を動かすことができます。
$ start-dfs.sh
HDFS の停止用には stop-dfs.sh があるので、停止する時はそちらを使います。

HDFS ファイルシステム内にディレクトリを作る

Hadoop に読ませるファイルを HDFS に配置したり、分析結果を出力させたりするために、あらかじめディレクトリを作っておきます。
ここはいわば作業ディレクトリとなるようです。
$ hdfs dfs -mkdir /user
$ hdfs dfs -mkdir /user/hadoop

Hadoop でテキストファイルを分析する

実際に Hadoop でテキストファイルを分析してみます。
分析といっても今回は grep コマンド相当のことをしてみるだけです。Hadoop に読ませるサンプルのアクセスログファイルを用意し、アクセス元 IP を抽出してみます。

分析用のアクセスログを用意する

分析用に以下のようなテキストファイルを用意してみました。とりあえず 3 つ置いておきます。
$ cat accesslog01.log
192.168.0.1 - - [21/Mar/2017:10:09:18 +0900] "GET /book/1 HTTP/1.1" 200 2078 "/" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"
192.168.0.2 - - [21/Mar/2017:10:09:18 +0900] "GET /book/2 HTTP/1.1" 200 2078 "/" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"
192.168.0.4 - - [21/Mar/2017:10:09:18 +0900] "GET /book/3 HTTP/1.1" 200 2078 "/" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"

$ cat accesslog02.log
192.168.0.1 - - [21/Mar/2017:10:09:18 +0900] "GET /book/1 HTTP/1.1" 200 2078 "/" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"
192.168.0.2 - - [21/Mar/2017:10:09:18 +0900] "GET /book/2 HTTP/1.1" 200 2078 "/" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"
192.168.0.5 - - [21/Mar/2017:10:09:18 +0900] "GET /book/3 HTTP/1.1" 200 2078 "/" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"

$ cat accesslog03.log
192.168.0.2 - - [21/Mar/2017:10:09:18 +0900] "GET /book/1 HTTP/1.1" 200 2078 "/" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"
192.168.0.3 - - [21/Mar/2017:10:09:18 +0900] "GET /book/2 HTTP/1.1" 200 2078 "/" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"
192.168.0.6 - - [21/Mar/2017:10:09:18 +0900] "GET /book/3 HTTP/1.1" 200 2078 "/" "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"

これらの分析用テキストファイルを HDFS ファイルシステム内に配置します。
input ディレクトリを作成し、その中に先ほどのテキストファイルを配置します。
$ hdfs dfs -mkdir input
$ hdfs dfs -put accesslog*.log input

アクセスログからアクセス元 IP を抽出する

HDFS ファイルシステム内に配置したテキストファイルから単語を抽出し、その個数を数えてみます。
Hadoop が分析で利用するロジックを jar ファイルとして hadoop コマンドの引数に指定することができます。例えば hadoop-mapreduce-examples-2.8.0.jar は引数に grep を渡すと Linux の grep コマンドのように動作します。
先頭の数値が抽出したい IP になるので、grep する単語を正規表現で '^[0-9.]+' と指定してみます。
$ hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.8.0.jar grep input output '^[0-9.]+'

分析結果が HDFS ファイルシステムの output 内に配置されるので、直接中身を確認してみます。
$ hdfs dfs -cat output/*
3	192.168.0.2
2	192.168.0.1
1	192.168.0.6
1	192.168.0.5
1	192.168.0.4
1	192.168.0.3
アクセスログに記載された IP が個数順に集計されていますね。

分析結果を HDFS ファイルシステムからとりだすには、以下のコマンドを実行します。
$ hdfs dfs -get output output
とりだした分析結果をローカルマシンのファイルシステム上で cat してみると、先程 HDFS ファイルシステム内で確認した内容と同じ内容が書かれているのがわかります。
$ cat output/*
3	192.168.0.2
2	192.168.0.1
1	192.168.0.6
1	192.168.0.5
1	192.168.0.4
1	192.168.0.3

なお、一度分析結果を出力した HDFS ファイルシステム内のディレクトリは再利用ができないので、不要になったタイミングで適宜消しておきましょう。
$ hadoop fs -rm -r output
これは、逆に言えば、一度分析した結果は HDFS 内に永続化されるということになります。
一度分析した結果を 1 週間利用するというケースでは、分析処理は 1 度だけ行い、それ移行は既に分析済みの結果を読み込むのみでよいということですね。

おわり

ひとまず Hadoop で遊んでみようということで、Pseudo-Distributed Mode での動作を簡単に試してみました。
今回試した grep 処理でも、データ量の割には結構な時間がかかっているのがわかると思います。少量のデータに対しては、Linux の grep なら遥かに高速ですが、これは逆に大量データを相手にする際には Hadoop に軍配が上がってくるのだと思います。また一回の分析処理にかかる時間を短縮する試みや、様々な面での使い勝手を改善するための周辺技術も多く存在しているので、その辺についてもまた折をみて試してみたいなと思います。
  WEB 技術Hadoop  コメント (0)  2017/03/29 18:42:18


公開範囲:
プロフィール HN: ももかん
ゲーム作ったり雑談書いたり・・・していた時期が私にもありました。
カレンダー
<<2018, 7>>
1234567
891011121314
15161718192021
22232425262728
2930311234