1月 202012
 

Hadoopで始める並列データ解析/前編 | Inhale n’ Exhale1月13日(金)にPalo Altoで行われたJTPAのギークサロンに参加してきた。今回は参加者がラップトップ持ち込みでコーディングしていくハッカソン形式で、会場入りする前までにHadoopが使える環境を自前で用意しておく必要があった。もうそれだけで、いつものギークサロンよりハードルが高いのだが、当日は15人ほどのギークたち(中には3日前にベイエリアに来たばかりという学生もいた)が集まって、おのおのラップトップとにらめっこしながらHadoopと戯れていた。

今回のギークサロンをホストしてくださった山中仁氏が、EC2上にHadoopクラスタを構築する方法を、参加者向けの資料としてWeb上に準備してくださり、「Hadoop=未知の領域」だった自分でもすんなりHadoopクラスタを組むことができた。だが残念なことに、この資料自体がEC2上に一時的に立てたサーバーに置かれており情報が恒久的には残らないとのこと(山中氏談)なので、山中氏に一部転載の許可をいただき、自分なりの咀嚼も含めてEC2上にHadoopクラスタを構築する手順を書き留めておくことにした。

概要

Hadoopは並列分散処理を行うための仕組みなので、当然のことながら複数台のマシンを用意する必要がある。自前で物理的なマシンを並べたり、ローカルに仮想マシンを並べたりすることも可能だが、手っ取り早くHadoopを動かすのであれば、Amazon EC2を使うのが時間的にも金銭的にも手軽である。

大まかな手順としては、まずHadoopをコントロールするためのLinuxマシンをEC2上に用意する。そこにHadoopとEC2 API Toolsをインストールして、Hadoopを利用するための環境をセットアップする。計算処理を行うためのHadoopクラスタを立ち上げ、処理用の入力データをアタッチして、メインとなる処理を実行する。最後に処理結果の出力データを抽出する。

Amazon EC2へのサインアップ

なによりも先に、AWS (Amazon Web Services)、およびEC2 (Elastic Compute Cloud)が使えなければならないので、AWSのアカウントを持っていない場合は、以下のサイトを参考にしてサインアップしよう。

AWSにサインアップしたら(既にAWSアカウントを持っている場合も同じ)、AWSのホームページの右上にあるMy Account / ConsoleからAWS Management Consoleをクリックする。

メールアドレスとパスワードを入力してサインインしよう。

EC2上でLinuxマシンを起動

管理コンソールが開いたらEC2のタブを選択する。左側のNavigationメニューにあるRegionは[US East]にしておく(インスタンス費が一番安いので)。今回AWSにサインアップしたばかりの人は、無料なので気にすることはないだろう。

次にEC2上でクライアントとして起動させるLinuxのマシンイメージ(AMI)を選択する。Linuxのディストリビューションは好みもあるだろうが、ここではUbuntu 10.10の公開AMIリストからEBS上でブートできる64ビットマシンを使うことにする。なお、Ubuntuの他のバージョンの公開AMIリストは、EC2スターターズガイドから辿ることができる。US EastリージョンでEBSブータブルな64ビットマシンのAMIを探すと、ami-cf33fea6というAMIが見つかる。後ほど検索に使うのでイメージIDをメモしておく。

管理コンソールに戻り、Regionが[US East]になっていることを確認して、EC2 Dashboardに表示されている[Launch Instance]ボタンをクリックする。

[Launch Classic Wizard]を選択して、[Continue]ボタンをクリックする。

[Community AMIs]タブを選択して、上部の検索フォームに先ほどメモしておいたami-cf33fea6を入力すると、UbuntuのAMIが見つかるので[Select]ボタンをクリックする。

インスタンスの種類は一番下のスペックでも十分なのでMicroインスタンスを選択。Availability Zoneは[us-east-1c]を選んで、[Continue]ボタンをクリックする。

このページはデフォルトのまま[Continue]ボタンをクリック。

このページも基本デフォルトのままでもいいが、他にもEC2のインスタンスを立ち上げている場合は、EC2 Dashboardでインスタンスを見つけやすいように名前を付けておくといいだろう。

UbuntuにSSHでアクセスする際に使用するRSA秘密鍵/公開鍵の鍵ペアを新たに作成する。鍵ペアの名前をここではec2-hadoopとして、[Create & Download your Kay Pair]をクリックすると、ec2-hadoop.pemというファイルがダウンロードされる。SSHでアクセスする際に必要になる秘密鍵なので、うっかり消さないように要注意(失くしたらまた新しい鍵ペアを作らなければならない)。

UbuntuにSSHでアクセスできるようにするためファイアウォールに穴を開ける。[Create a new Security Group]のラジオボタンを選んで、Group NameとGroup Descriptionはわかりやすいようなものを入力しておく。[Create a new Rule]でSSHを選択して[Add Rule]ボタンをクリックする。右側の一覧にSSHが追加されたことを確認したら[Continue]ボタンをクリックする。

最後にウィザードで設定した内容の確認ページが表示され、[Launch]ボタンをクリックすると、EC2上にUbuntuのインスタンスが作成・起動される。

EC2の管理コンソールで左側のNavigationメニューからInstancesを選ぶと、インスタンスの起動状態が確認できる。

最後に必須ではないが、もし今回AWSにサインアップしたばかりであれば、Elastic IPが1つ無料で使えるらしいので、インスタンスにグローバルIPを割り当てておくといいだろう。NavigationメニューからElastic IPsを選び、[Allocate New Address]ボタンをクリックすると、さらにダイアログが出てくるので[Yes, Allocate]ボタンをクリックする。

追加されたElastic IPを右クリックすると、[Release]と[Associate]というプルダウンが出てくるので、[Associate]をクリック。Elastice IPを割り当てるインスタンスに、先ほど起動させたhadoop-clientを選択して[Yes, Allocate]ボタンをクリックする。

Elastic IPを使わない場合は、インスタンス起動時に割り当てられるパブリックDNS名でアクセスすることになる。NavigationメニューのInstancesからhadoop-clientのインスタンスを選択して、画面下部に表示される詳細情報にあるPublic DNSをメモしておこう。Elastic IPを使えばインスタンスを再起動しても同じIPアドレスでアクセスできるが、パブリックDNSはインスタンスが起動するたびにコロコロ変わる。短時間で遊ぶ分にはパブリックDNSでも十分だろう。

えらくスペースを割いてしまったが、ここまではHadoopはまったく関係ない。EC2上にLinuxマシンを立ち上げたに過ぎない。

HadoopとEC2 API Toolsのインストール

EC2をセットアップする過程でダウンロードしたSSH用の秘密鍵を使って、UbuntuのインスタンスにSSHでログインして、Hadoopに必要なソフトをインストールしていく。WindowsならばTeraTermPuTTYを使う。Linux/Macならばターミナルからアクセスする。

ダウンロードした秘密鍵(ec2-hadoop.pem)は、~/.sshディレクトリに移動してパーミッションを600に変更する。ファイル名も秘密鍵だとわかるようにid_rsa.ec2-hadoopに変更しておく。

local$ mv ~/Downloads/ec2-hadoop.pem ~/.ssh/id_rsa.ec2-hadoop
local$ chmod 600 ~/.ssh/id_rsa.ec2-hadoop

インスタンスにElastic IPを割り当てた場合はIPアドレスを、Elastic IPを使っていない場合はパブリックDNSを、接続先のホストとして指定することになる。Ubuntuコミュニティが提供しているAMIには予めubuntuというユーザーが作られているので、このアカウントを使ってログインする。sshで指定するオプションが非常に長くなるので、~/.bashrcあたりにエイリアスを書いおこう。

export EC2_HADOOP_HOST="ec2-50-17-70-166.compute-1.amazonaws.com"
export EC2_HADOOP_KEY=~/.ssh/id_rsa.ec2-hadoop
alias ec2hadoop="ssh -i $EC2_HADOOP_KEY ubuntu@$EC2_HADOOP_HOST"

これでec2hadoopとタイプするだけで、Ubuntuにログインできるようになる。

local$ . ~/.bashrc
local$ ec2hadoop
The authenticity of host 'ec2-50-17-70-166.compute-1.amazonaws.com (50.17.70.166)' can't be established.
RSA key fingerprint is 66:65:ef:40:2a:49:67:e2:dd:4e:42:d3:00:a2:f4:ad.
Are you sure you want to continue connecting (yes/no)? yes

ubuntu$

まずはHadoopとEC2 API Toolsを動作させるためにJDKをインストールする。

ubuntu$ sudo apt-add-repository "deb http://archive.canonical.com/ lucid partner"
ubuntu$ sudo apt-get update
ubuntu$ sudo apt-get install sun-java6-jdk

次にEC2 API Toolsをインストールする。

ubuntu$ sudo apt-add-repository ppa:awstools-dev/awstools
ubuntu$ sudo apt-get update
ubuntu$ sudo apt-get install ec2-api-tools

最後にHadoopをダウンロードして、/usr/localに展開する。

ubuntu$ wget www.gtlib.gatech.edu/pub/apache/hadoop/core/hadoop-1.0.0/hadoop-1.0.0.tar.gz
ubuntu$ tar -zxf hadoop-1.0.0.tar.gz
ubuntu$ sudo mv hadoop-1.0.0 /usr/local/hadoop

UbuntuにHadoop、EC2 API Toolsをインストールする方法は、EC2スターターズガイドでも紹介されているので参考に。

EC2-Hadoopクラスタの設定

HadoopにはデフォルトでEC2上にクラスタを構築する機能が搭載されている。これを利用するために必要なセットアップを行っていく。

まず、HadoopがEC2にアクセスするためのX.509証明書と秘密鍵を、AWSの管理コンソールからダウンロードする。AWSの管理コンソールの右上にあるアカウントメニューから[Security Credentials]をクリックする。

Access Credentialsの[X.509 Certificates]タブを選択して[Create a new Certificate]をクリックする。

[Download Private Key File]ボタンと[Download X.509 Certificate]ボタンをそれぞれクリックすると、秘密鍵とX.509証明書がダウンロードされる。ダウンロードが完了したら[Close]ボタンをクリックする。

ダウンロードしたX.509証明書と秘密鍵を、EC2上のUbuntuにscpでアップロードする。Windowsの場合は、WinSCPを使うといいだろう。

local$ cd ~/Downloads
local$ mv pk-XXXXXXXXXXXXXXXXXXXXXXXXXXXX.pem pk.pem
local$ mv cert-XXXXXXXXXXXXXXXXXXXXXXXXXXXX.pem cert.pem
local$ scp -i $EC2_HADOOP_KEY ~/Downloads/{pk,cert}.pem \
  ubuntu@$EC2_HADOOP_HOST:/home/ubuntu

なお、Ubuntuの環境はHadoopの利用専用で、かつ自分以外に他のユーザーが使わないという前提で設定している。もし、既存の共用Linux環境で設定する場合は、秘密鍵の保存ディレクトリやパーミッションを適切に設定するように。

Ubuntuに再度SSHでログインして、HadoopとEC2 API Toolsを使う上で必要になる環境変数を~/.profileに追記していく。

local$ ec2hadoop
ubuntu$ vi .profile
# 以下のスクリプトを追記する
export JAVA_HOME="/usr/lib/jvm/java-6-sun"
export EC2_HOME="/usr/lib/ec2-api-tools"
export HADOOP_HOME="/usr/local/hadoop"
export PATH="$PATH:$EC2_HOME/bin:$HADOOP_HOME/bin:$HADOOP_HOME/src/contrib/ec2/bin"
export EC2_PRIVATE_KEY="$HOME/pk.pem"
export EC2_CERT="$HOME/cert.pem"

~/.profileを読み込んで、ec2-describe-instancesコマンドが実行できることを確認する。

ubuntu$ . .profile
ubuntu$ ec2-describe-instances

UbuntuがHadoopクラスタとの通信するために使うアクセスキーを、id_rsa-gsg-keypairというファイルに保存する。id_rsa-gsg-keypairファイルは$EC2_PRIVATE_KEYが保存されているディレクトリと同じにする必要がある。また、パーミッションは600に設定する。

ubuntu$ ec2-add-keypair gsg-keypair | tail -n +2 > id_rsa-gsg-keypair
ubuntu$ chmod 600 id_rsa-gsg-keypair

最後にhadoop-ec2-env.shを編集して、HadoopのEC2クラスタ用の環境変数を設定する。

ubuntu$ vi $HADOOP_HOME/src/contrib/ec2/bin/hadoop-ec2-env.sh

設定が必要な箇所は18~25行目にある3つの変数。

  • AWS_ACCOUNT_ID
  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY

AWS_ACCOUNT_IDは、AWSのSecurity Credentialsページの右上、Account Numberに表示されている12桁の数字(設定時はハイフンを取り除く)。

次にアクセスキーを作成する。同じくSecurity CredentialsページにあるAccess Credentialsの[Access Keys]タブを選択して[Create a new Access Key]をクリックする。

AWS_ACCESS_KEY_IDには、作成したアクセスキーの[Access Key ID]欄の文字列を指定する。AWS_SECRET_ACCESS_KEYには[Show]をクリックしたときに表示される文字列を設定する。

hadoop-ec2-env.shを保存したら、いよいよHadoopのクラスタを立ち上げる。

ubuntu$ hadoop-ec2 launch-cluster hadoop-cluster 2

3番目の引数hadoop-clusterはクラスタ群に付ける名前なので任意で構わない。最後の引数では起動するスレーブクラスタの数(今回は2台)を指定している。クラスタの起動にはかなり時間がかかるので、コーヒーでも飲みながら待つこととしよう。

これでHadoopを使うための準備は完了である。EC2をセットアップするところから説明してきているので非常に面倒な気もするが、物理マシンや仮想マシンを自前で用意するよりもずっと楽なはず。

クラスタの起動が完了したら、Hadoopのマスタークラスタにログインして、試しにサンプルの円周率計算ソフトを実行してみよう。

ubuntu$ hadoop-ec2 login hadoop-cluster
cluster# hadoop jar $HADOOP_HOME/hadoop-0.19.0-examples.jar pi 10 10000000
Number of Maps = 10 Samples per Map = 10000000
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
12/01/19 21:41:34 INFO mapred.FileInputFormat: Total input paths to process : 10
12/01/19 21:41:35 INFO mapred.JobClient: Running job: job_201201192136_0001
12/01/19 21:41:36 INFO mapred.JobClient:  map 0% reduce 0%
12/01/19 21:41:48 INFO mapred.JobClient:  map 10% reduce 0%
12/01/19 21:41:53 INFO mapred.JobClient:  map 20% reduce 0%
12/01/19 21:42:00 INFO mapred.JobClient:  map 30% reduce 0%
12/01/19 21:42:01 INFO mapred.JobClient:  map 40% reduce 0%
12/01/19 21:42:03 INFO mapred.JobClient:  map 50% reduce 0%
12/01/19 21:42:04 INFO mapred.JobClient:  map 60% reduce 0%
12/01/19 21:42:09 INFO mapred.JobClient:  map 70% reduce 0%
12/01/19 21:42:11 INFO mapred.JobClient:  map 80% reduce 0%
12/01/19 21:42:14 INFO mapred.JobClient:  map 90% reduce 6%
12/01/19 21:42:17 INFO mapred.JobClient:  map 100% reduce 20%
12/01/19 21:42:22 INFO mapred.JobClient:  map 100% reduce 26%
12/01/19 21:42:23 INFO mapred.JobClient:  map 100% reduce 100%
12/01/19 21:42:24 INFO mapred.JobClient: Job complete: job_201201192136_0001
12/01/19 21:42:24 INFO mapred.JobClient: Counters: 16
12/01/19 21:42:24 INFO mapred.JobClient:   File Systems
12/01/19 21:42:24 INFO mapred.JobClient:     HDFS bytes read=1180
12/01/19 21:42:24 INFO mapred.JobClient:     HDFS bytes written=255
12/01/19 21:42:24 INFO mapred.JobClient:     Local bytes read=366
12/01/19 21:42:24 INFO mapred.JobClient:     Local bytes written=1066
12/01/19 21:42:24 INFO mapred.JobClient:   Job Counters 
12/01/19 21:42:24 INFO mapred.JobClient:     Launched reduce tasks=1
12/01/19 21:42:24 INFO mapred.JobClient:     Launched map tasks=10
12/01/19 21:42:24 INFO mapred.JobClient:     Data-local map tasks=10
12/01/19 21:42:24 INFO mapred.JobClient:   Map-Reduce Framework
12/01/19 21:42:24 INFO mapred.JobClient:     Reduce input groups=2
12/01/19 21:42:24 INFO mapred.JobClient:     Combine output records=0
12/01/19 21:42:24 INFO mapred.JobClient:     Map input records=10
12/01/19 21:42:24 INFO mapred.JobClient:     Reduce output records=0
12/01/19 21:42:24 INFO mapred.JobClient:     Map output bytes=320
12/01/19 21:42:24 INFO mapred.JobClient:     Map input bytes=240
12/01/19 21:42:24 INFO mapred.JobClient:     Combine input records=0
12/01/19 21:42:24 INFO mapred.JobClient:     Map output records=20
12/01/19 21:42:24 INFO mapred.JobClient:     Reduce input records=20
Job Finished in 50.49 seconds
Estimated value of PI is 3.14146444

3.141までしか計算合ってないが…とりあえず動いていることは確認できた。

立ち上げたクラスタをそのまま放置してしまうとEC2で課金されてしまうので、不要になったらクラスタを落としておこう。自分はギークサロンの前日に準備だけして当日まで放置しておいたら、HadoopのクラスタがLinuxのSmallインスタンスとして起動することもあり(マスタークラスタ1台とスレーブクラスタ2台の計3台分)、一晩で$6くらい課金されてしまったorz

hadoop-ec2 terminate-cluster hadoop-cluster

参考サイト

後編に続く

  3 コメント

 返信する

以下のHTML タグと属性が利用できます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(required)

(required)

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください