Apache Hadoop はビッグデータ処理基盤を構築するための超有名なオープンソースソフトウェア。 Google の発表した論文を元にして MapReduce アルゴリズムと Hadoop Distributed File System (HDFS) が実装されている。 この Hadoop/HDFS を中心として Apache Hive や Apache HBase などのミドルウェアが動作する一大エコシステムが形成されている。 今回は、そんな Apache Hadoop を CentOS7 で使ってみることにする。
尚、Apache Hadoop 関連の OSS をインストールするときは、いくつかの会社が出しているディストリビューションを利用することが多い。 例えば Cloudera CDH や Hortonworks HDP など。 しかし、今回はそれらのディストリビューションを使うのではなく Apache が出しているパッケージをそのまま使ってみる。 その方が内部でどんなことをやっているのかとか、どのように設定すれば良いのか理解が深まるだろうと考えたため。
ちなみに、Apache Hadoop は以下に示す三つの動作モードがある。
- ローカルモード
- 一つのホストで動作する
- HDFS を使わない
- 疑似分散モード
- 一つのホストで動作する
- HDFS を使う
- 完全分散モード
- 複数のホストで動作する
- HDFS を使う
今回は、その中でも疑似分散モードを試すことにした。 実運用に乗せる環境なら確実に完全分散モードになるけど、手元での検証用なら疑似分散モードでも十分に使えそうなので。 ちなみに HDFS というのは複数のホストに細切れにしたファイルを配布した上で、それを各ホストで並列処理できる仕組みを備えたファイルシステムになっている。
疑似分散モード、というよりローカルモードを含むシングルホストで動かすときに参照するドキュメントは次の通り。
Apache Hadoop 2.8.0 – Hadoop: Setting up a Single Node Cluster.
もし完全分散モードなら、このドキュメントを参照する。
Apache Hadoop 2.8.0 – Hadoop Cluster Setup
使った環境は次の通り。
$ cat /etc/redhat-release CentOS Linux release 7.3.1611 (Core) $ uname -r 3.10.0-514.16.1.el7.x86_64
Java をインストールする
Hadoop 関連のソフトウェアは、その多くが JVM 言語で書かれている。 なので、まずは Java をインストールしておこう。 一応、動作確認が取れているバージョンはこのページにあった。
HadoopJavaVersions - Hadoop Wiki
OpenJDK だと 1.7 しか今のところ確認されていないっぽい。
とはいえ、まあ動かないなんてことはないだろうという考えで 1.8 を入れてみることにする。
jps
コマンドが使いたいのでインストールするのを JDK にする。
$ sudo yum -y install java-1.8.0-openjdk-devel
java
コマンドが使えることが確認する。
$ java -version openjdk version "1.8.0_131" OpenJDK Runtime Environment (build 1.8.0_131-b11) OpenJDK 64-Bit Server VM (build 25.131-b11, mixed mode)
Apache Hadoop をローカルモードで動かす
まずは Apache Hadoop をダウンロードした上でローカルモードで動かしてみる。 というより、何も設定しない状態ではローカルモードとして動作する。
ひとまず最低限必要なパッケージを一通り入れておく。
$ sudo yum -y install openssh-clients rsync wget
次に Apache Hadoop をダウンロードする。
$ wget http://ftp.riken.jp/net/apache/hadoop/common/hadoop-2.8.0/hadoop-2.8.0.tar.gz
Apache Hadoop のミラーサイトは次の通り。 好きなところを選んでダウンロードしよう。
ダウンロードできたら解凍する。
$ tar xf hadoop-2.8.0.tar.gz
解凍してできたディレクトリに移動しよう。
$ cd hadoop-2.8.0/
Hadoop を動かすには環境変数として JAVA_HOME
が設定されている必要がある。
そのため、先ほどインストールした OpenJDK のディレクトリを指定する。
$ export JAVA_HOME=/usr/lib/jvm/jre-1.8.0-openjdk
あるいは、起動時の環境変数を etc/hadoop/hadoop-env.sh
で指定することもできる。
設定を永続化したいときは、こちらを使えば良さそう。
$ sed -i -e ' s:^export JAVA_HOME=.*$:export JAVA_HOME=/usr/lib/jvm/jre-1.8.0-openjdk: ' etc/hadoop/hadoop-env.sh
これで hadoop
コマンドがエラーにならず実行できるようになる。
$ bin/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 /home/vagrant/hadoop-2.8.0/share/hadoop/common/hadoop-common-2.8.0.jar
いくつかサンプルプログラムを動かしてみよう。
これには hadoop
コマンドに付属のサンプルプログラムの入った jar
ファイルを指定する。
例えば、これは円周率を計算するもの。
$ bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.8.0.jar pi 10 100000 Number of Maps = 10 Samples per Map = 100000 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 ...(snip)... Job Finished in 1.526 seconds Estimated value of Pi is 3.14155200000000000000
それ以外には、ディレクトリ内のファイルから特定の文字列を検索する grep
とか。
ローカルモードでは HDFS を使わないので OS のファイルシステムを直接使うことになる。
検索対象として input
ディレクトリの中に Hadoop の設定ファイルをコピーしておこう。
$ mkdir input $ cp etc/hadoop/*.xml input
input
ディレクトリの中にあるファイルから dfs
から始まる言葉を探してみる。
$ bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.8.0.jar grep input output 'dfs[a-z.]+'
結果は output
ディレクトリに出力される。
この例では dfsadmin という言葉が一つだけ見つかった。
$ cat output/*
1 dfsadmin
同じ文字列を使って設定ファイルを egrep
すると、たしかに一つだけ見つかる。
$ egrep 'dfs[a-z.]+' etc/hadoop/*.xml
etc/hadoop/hadoop-policy.xml: dfsadmin and mradmin commands to refresh the security policy in-effect.
疑似分散モード
続いては疑似分散モードで動かしてみる。 疑似分散モードでは一つのホストで完結しているもののファイルシステムとして HDFS を使うことになる。 これによって、より実運用に近づけた状態で動作確認ができる。
SSH でログインできるようにする
Hadoop は SSH 経由でホストを操作するので、あらかじめログインできるようにしておかないといけない。 そこで、パスワードなしの公開鍵のペアを作ってローカルホストに仕込んでおく。
$ ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa
$ ssh-copy-id -i ~/.ssh/id_rsa.pub localhost
ログインできることを確認しておこう。
$ ssh localhost
設定ファイル: etc/hadoop/core-site.xml
続いては設定ファイルを編集していく。
まずは etc/hadoop/core-site.xml
に接続先ファイルシステム (HDFS) の設定を仕込む。
$ cat << 'EOF' > /tmp/core-site.xml.property <property> <name>fs.defaultFS</name> <value>hdfs://localhost:9000</value> </property> EOF $ sed -i -e ' /^<configuration>$/r /tmp/core-site.xml.property /^$/d ' etc/hadoop/core-site.xml
こんな感じ。 これでローカルホストの HDFS に接続するようになる。
$ tail -n 6 etc/hadoop/core-site.xml <configuration> <property> <name>fs.defaultFS</name> <value>hdfs://localhost:9000</value> </property> </configuration>
設定ファイル: etc/hadoop/hdfs-site.xml
続いては etc/hadoop/hdfs-site.xml
で HDFS の設定をする。
ここでは、ファイルのレプリケーション数を 1
に設定する。
HDFS では冗長性を担保するために、複数のホストで同じデータを重複して持つ。
これが HDFS のレプリケーション数と呼ばれるもので、デフォルトでは 3
になっている。
シングルホストで動く疑似分散モードでは、レプリケーション数は 1
にするしかない。
$ cat << 'EOF' > /tmp/hdfs-site.xml.property <property> <name>dfs.replication</name> <value>1</value> </property> EOF $ sed -i -e ' /^<configuration>$/r /tmp/hdfs-site.xml.property /^$/d ' etc/hadoop/hdfs-site.xml
こんな感じになる。
$ tail -n 6 etc/hadoop/hdfs-site.xml <configuration> <property> <name>dfs.replication</name> <value>1</value> </property> </configuration>
HDFS をセットアップする
ここまで設定できたら HDFS をフォーマットする。
$ bin/hdfs namenode -format
そして、必要なサービス (デーモン) を起動する。
$ sbin/start-dfs.sh
上記を実行したら、ログにエラーメッセージなどが出ていないことを確認しておこう。
$ grep -ir ERROR logs/*
また、次のように jps
を確認してネームノード、データノード、セカンダリネームノードが動作していれば良い。
ネームノードは HDFS のメタデータなどを保持するマスターサーバのこと。
データノードは、実際のデータを格納しているスレーブサーバのようなもの。
セカンダリネームノードはその名の通りネームノードのセカンダリ。
$ jps 28720 NameNode 28849 DataNode 29012 SecondaryNameNode 29129 Jps
ここまでで hdfs
コマンドが使えるようになる。
このコマンドを経由して HDFS の操作を行う。
使い方は一般的な POSIX のファイルシステムと基本的には似通っている。
ひとまず作業用にホームディレクトリを作ってみよう。
$ bin/hdfs dfs -mkdir -p /user/$(whoami)
すると、こんな感じでディレクトリが作られる。
$ bin/hdfs dfs -ls -R / drwxr-xr-x - vagrant supergroup 0 2017-05-15 21:16 /user drwxr-xr-x - vagrant supergroup 0 2017-05-15 21:16 /user/vagrant
ちなみに、HDFS で操作した実体はもちろん OS のファイルシステム上に存在している。
デフォルトでは /tmp/hadoop-<username>
に作られる。
$ ls /tmp/hadoop-$(whoami)
先ほどと同じように grep
のサンプルプログラムを動かすために input
ディレクトリを作る。
その上でローカルのファイルシステムにある設定ファイルを HDFS のディレクトリ内にコピーしよう。
$ bin/hdfs dfs -mkdir input $ bin/hdfs dfs -put etc/hadoop/*.xml input
上記ができたらサンプルプログラムを実行する。
$ bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.8.0.jar grep input output 'dfs[a-z.]+'
実行が終わったら結果が出力されているディレクトリを HDFS からローカルのファイルシステムにコピーする。
$ bin/hdfs dfs -get output output2
結果を見ると、次のようになった。
$ cat output2/* 1 dfsadmin 1 dfs.replication
二つに増えているのは疑似分散モードで動かすための設定に dfs から始まる文字列が含まれていたため。
$ egrep 'dfs[a-z.]+' etc/hadoop/*.xml etc/hadoop/hadoop-policy.xml: dfsadmin and mradmin commands to refresh the security policy in-effect. etc/hadoop/hdfs-site.xml: <name>dfs.replication</name>
ちなみに、後片付けとして HDFS のサービス (デーモン) を停止するには、次のようにする。
$ sbin/stop-dfs.sh
YARN/MRv2 で動かす
実は Hadoop には一口に MapReduce といっても複数の実装がある。 それが、先ほど動かした MRv1 と、これから動かす YARN/MRv2 というもの。 まだ違いがよく分かっていないんだけど、YARN/MRv2 は MRv1 に存在した問題を解消するために作られたらしい。 主に、スケーラビリティや汎用性が改善されているっぽい。
設定ファイル: etc/hadoop/mapred-site.xml
ここからは、また設定ファイルを編集していく。
まずは設定ファイル etc/hadoop/mapred-site.xml
のテンプレートをコピーしてくる。
$ cp etc/hadoop/mapred-site.xml{.template,}
その上で MapReduce のフレームワークとして YARN が使われるようにする。
$ cat << 'EOF' > /tmp/mapred-site.xml.property <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property> EOF $ sed -i -e ' /^<configuration>$/r /tmp/mapred-site.xml.property /^$/d ' etc/hadoop/mapred-site.xml
こんな感じ。
$ tail -n 6 etc/hadoop/mapred-site.xml <configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property> </configuration>
設定ファイル: etc/hadoop/yarn-site.xml
次は YARN 自体の設定を etc/hadoop/yarn-site.xml
に書き込む。
$ cat << 'EOF' > /tmp/yarn-site.xml.property <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> EOF $ sed -i -e ' /^<configuration>$/r /tmp/yarn-site.xml.property /^$/d ' etc/hadoop/yarn-site.xml
こうなる。
$ tail -n 7 etc/hadoop/yarn-site.xml <configuration> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> <!-- Site specific YARN configuration properties --> </configuration>
あとは YARN のサービス (デーモン) を起動する。
$ sbin/start-yarn.sh
先ほどと同じようにログにエラーメッセージが出ていないか確認しておく。
$ grep -ir ERROR logs/*
次のようにリソースマネージャとノードマネージャが起動していれば良い。
$ jps 28720 NameNode 28849 DataNode 29602 Jps 29012 SecondaryNameNode 29194 ResourceManager 29309 NodeManager
YARN/MRv2 でサンプルプログラムを動かしてみる
YARN/MRv2 は MapReduce の実行フレームワークが異なるだけで基本的には MRv1 と同じプログラムが使えるらしい。
先ほどと同じようにサンプルプログラムを動かしてみよう。
一旦、さっき使ったディレクトリを削除して、改めて設定ファイルをコピーしておく。
今度は XML
以外のファイルも対象に含めてみる。
$ bin/hdfs dfs -rm -r -f input output $ bin/hdfs dfs -put etc/hadoop input
grep
のサンプルプログラムを実行する。
理由は分からないけど、今回はやたらと時間がかかった。
ただファイルが増えただけが理由なのか YARN/MRv2 を使っているせいなのか。
$ bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.8.0.jar grep input output 'dfs[a-z.]+'
終わったら実行結果を HDFS からローカルのファイルシステムにコピーする。
$ bin/hdfs dfs -get output output3
次のように dfs
から始まる文字列が見つかった。
$ cat output3/* 6 dfs.audit.logger 4 dfs.class 3 dfs.logger 3 dfs.server.namenode. 2 dfs.audit.log.maxbackupindex 2 dfs.period 2 dfs.audit.log.maxfilesize 1 dfs.log 1 dfs.file 1 dfs.servers 1 dfsadmin 1 dfsmetrics.log 1 dfs.replication
後片付けするときは次のようにして YARN のサービス (デーモン) を停止する。
$ sbin/stop-yarn.sh
まとめ
今回は素の Apache Hadoop を CentOS7 の上で使ってみた。 動作モードとしてはシングルホスト上で HDFS と共に動作する疑似分散モードを選んだ。 実運用するなら完全分散モードになるけど、手元での動作検証用なら有用といえそうだ。 ビッグデータを扱う上で Apache Hadoop 関連のプロダクトは避けて通れないので、今後も知見を集めていきたい。
Apache Hadoop の概念や動作原理的な部分は、この本が分かりやすかった。 ただし、この本では発売時期的に MRv1 しか扱っておらず YARN/MRv2 については書かれていない。
Hadoop徹底入門 第2版 オープンソース分散処理環境の構築
- 作者: 太田一樹,岩崎正剛,猿田浩輔,下垣徹,藤井達朗,山下真一,濱野賢一朗
- 出版社/メーカー: 翔泳社
- 発売日: 2013/07/09
- メディア: 大型本
- この商品を含むブログ (5件) を見る
スマートPythonプログラミング: Pythonのより良い書き方を学ぶ
- 作者: もみじあめ
- 発売日: 2016/03/12
- メディア: Kindle版
- この商品を含むブログ (1件) を見る