Monthly Archives: 7月 2013

[Hadoop] Hadoop Streaming / mapperとreducerにPythonを使ってみる。

Pocket

 

HadoopはJavaで作られている。
だからHadoopに何か操作をさせたい場合には、通常、Javaで記述する必要がある。
しかしHadoopにはHadoop Streamingという仕組みがあり、早い話UNIXのStandard Stream要するに標準入出力を扱うことができる。

すなわち、UNIXの標準入出力の流儀に則ってさえいれば、お好きな言語で操作ができる。
Javaがまったく合わない私としては、Hadoop Streamはとてもありがたい。
これがなければHadoopに手を付ける気にはならなかった。

Hadoop Streamに必要なもの。

mapperとreducerを、好きな言語で書くだけ。
べつにmapperだけでもよいけど。
私はPython。

Hadoop streamにおけるmapperとreducerの概要。

mapperは何らかの入力を得て、キーと値(key, value)を出力する。
reducerはmapperからのkey, valueを受けて、keyごとにvalueを処理する。

なお、mapperの出力がreducerに渡されるとき、Hadoopがkeyごとにソートしてくれる。
この点はreducerの処理を簡単にする。詳細は後述。

試しにやってみること。

LAN向けのApacheのアクセス状況をカウントしてみる。
IPアドレスごとのアクセス回数だ。
ログは以下のようなもの。
アクセス元はすべてIPアドレスで記録されている。

192.168.100.106 - - [24/Jul/2013:22:35:26 +0900] "GET /MT/js/common/Editor/Iframe.js?v=5.14-ja HTTP/1.1" 304 - "http://192.168.100.5/MTcgi/mt.cgi?__mode=view&_type=entry&blog_id=2&id=330" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:22.0) Gecko/20100101 Firefox/22.0"
192.168.100.106 - - [24/Jul/2013:22:35:26 +0900] "GET /MT/js/common/Editor/Textarea.js?v=5.14-ja HTTP/1.1" 304 - "http://192.168.100.5/MTcgi/mt.cgi?__mode=view&_type=entry&blog_id=2&id=330" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:22.0) Gecko/20100101 Firefox/22.0"
192.168.100.106 - - [24/Jul/2013:22:35:26 +0900] "GET /MT/mt.js?v=5.14-ja HTTP/1.1" 304 - "http://192.168.100.5/MTcgi/mt.cgi?__mode=view&_type=entry&blog_id=2&id=330" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:22.0) Gecko/20100101 Firefox/22.0"

 

処理の流れ

1.mapperは、アクセスログからIPアドレスを抜き出す。
そして「<IPアドレス><タブ>1」を出力する。
これは、たとえば「192.168.1.1」から「1」回アクセスがあったよ、という意味。

2.hadoopがIPアドレスをキーにソート。

3.reducerは、IPアドレスごとに回数をカウントし、
「<IPアドレス><タブ><集計回数>」を出力する。

mapper.py

IPアドレスは、Apacheログにおいて、スペースを区切りにした第一フィールドに記載される。
だから一行ずつログを読んで、行頭のIPアドレスを抜き出し、その都度「<IPアドレス><タブ>1」を出力する。
「if “newsyslog” not in line:」は、システムメッセージ行を読み飛ばすため。

#!/usr/bin/env python

import sys

for line in sys.stdin:
        if "newsyslog" not in line:
                fields = line.strip().split()
                print '%s\t%s' % (fields[0],1)

実行権限も忘れずにつける。

$ chmod a+x ./mapper.py

実験。意図したとおり動いていますね。

$ cat ../input/httpd-access.log |./mapper.py 

192.168.100.107 1
192.168.100.106 1
192.168.100.110 1
192.168.100.107 1
192.168.100.107 1
192.168.100.107 1

 

reducer.py

mapper.pyからの出力は、ソートされてreducer.pyに入力される。
上記のmapper.py出力例は、以下のようにソートされる。

192.168.100.106 1
192.168.100.107 1
192.168.100.107 1
192.168.100.107 1
192.168.100.107 1
192.168.100.110 1

だからreducerとしては、第一フィールドを上から読んでいって、keyが変化したら、そこまでのカウント数を出力する。
そしてそのkeyの事は、さっぱり忘れて次のkeyのカウントに移ることができる。
もしソートがなされていないならば、入力の終わりまですべてのkeyを保持しなければならない。Hadoopに感謝である。

#!/usr/bin/env python

import sys

(last_key, count) = (None, 0)

for line in sys.stdin:
        (key, val) = line.strip().split("\t")

        if last_key and last_key != key:
                print "%s\t%s" % (last_key, count)
                (last_key, count) = (key,int(val))
        else:
                last_key = key
                count += int(val)

if last_key:
        print "%s\t%s" % (last_key, count)

実行権限を付ける。

 $ chmod a+x reducer.py

 

実験。間にsortを入れること。
問題なし。

$ cat ../input/httpd-access.log |./mapper.py |sort|./reducer.py 

127.0.0.1       567
192.168.100.106 327
192.168.100.107 671
192.168.100.109 2
192.168.100.150 193

 

Hadoopで動かしてみよう。

まずカウント対象となるログをHDFSにコピーする。

[hadoop@isis ~]$ hadoop dfs -put apachelog apachelog
[hadoop@isis ~]$
[hadoop@isis ~]$ hadoop dfs -ls
Found 1 items
drwxr-xr-x   - hadoop supergroup          0 2013-07-28 12:57 /user/hadoop/apachelog
[hadoop@isis ~]$
[hadoop@isis ~]$ hadoop dfs -ls apachelog
Found 1 items
-rw-r--r--   1 hadoop supergroup     999290 2013-07-28 12:57 /user/hadoop/apachelog/httpd-access.log
[hadoop@isis ~]$

実行。

hadoopにhadoop-streaming-1.0.0.jarを与え、input、outputのほかに、mapperとreducerも指定する。
-mapper -reducerとしてローカルファイルシステムでのパスを与える。
同時に、-fileでそれぞれのスクリプトを指定すると、スクリプトファイルをリモートのノードへ送ってくれる。

コマンドはすごく長くなる。
エスケープシーケンスを使って適宜改行し、見やすくしてタイプミスを防ぐ。

hadoop  jar \
/usr/local/share/hadoop/contrib/streaming/hadoop-streaming-1.0.0.jar \
    -input apachelog \
    -output apachelog.out \
    -mapper /home/hadoop/sandbox/mapper/mapper.py \
    -reducer /home/hadoop/sandbox/mapper/reducer.py \
    -file /home/hadoop/sandbox/mapper/mapper.py \
    -file /home/hadoop/sandbox/mapper/reducer.py

実際のログ

[hadoop@isis ~]$ hadoop  jar \
>    -output apachelog.out \
>    -mapper /home/hadoop/sandbox/mapper/mapper.py \
> /usr/local/share/hadoop/contrib/streaming/hadoop-streaming-1.0.0.jar \
>    -file /home/hadoop/sandbox/mapper/mapper.py \
>    -file /home/hadoop/sandbox/mapper/reducer.py \
>     -input apachelog \
>     -output apachelog.out \
>     -mapper /home/hadoop/sandbox/mapper/mapper.py \
>     -reducer /home/hadoop/sandbox/mapper/reducer.py \
>     -file /home/hadoop/sandbox/mapper/mapper.py \
>     -file /home/hadoop/sandbox/mapper/reducer.py

packageJobJar: [/home/hadoop/sandbox/mapper/mapper.py, /home/hadoop/sandbox/mapper/reducer.py, /tmp/hadoop-hadoop/hadoop-unjar1190814954490199586/] [] /tmp/streamjob8960127756596123730.jar tmpDir=null
13/07/28 13:30:15 INFO mapred.FileInputFormat: Total input paths to process : 1
13/07/28 13:30:43 INFO streaming.StreamJob: getLocalDirs(): [/tmp/hadoop-hadoop/mapred/local]
13/07/28 13:30:43 INFO streaming.StreamJob: Running job: job_201307281252_0001
13/07/28 13:30:43 INFO streaming.StreamJob: To kill this job, run:
13/07/28 13:30:43 INFO streaming.StreamJob: /usr/local/share/hadoop/bin/../bin/hadoop job  -Dmapred.job.tracker=localhost:8021 -kill job_201307281252_0001
13/07/28 13:30:43 INFO streaming.StreamJob: Tracking URL: http://localhost:50030/jobdetails.jsp?jobid=job_201307281252_0001
13/07/28 13:30:46 INFO streaming.StreamJob:  map 0%  reduce 0%
13/07/28 13:39:14 INFO streaming.StreamJob:  map 100%  reduce 0%
13/07/28 13:40:27 INFO streaming.StreamJob:  map 100%  reduce 33%
13/07/28 13:40:33 INFO streaming.StreamJob:  map 100%  reduce 67%
13/07/28 13:40:49 INFO streaming.StreamJob:  map 100%  reduce 100%
13/07/28 13:42:39 INFO streaming.StreamJob: Job complete: job_201307281252_0001
13/07/28 13:42:41 INFO streaming.StreamJob: Output: apachelog.out

 

結果の確認

hadoop dfs -catなどで。

[hadoop@isis ~]$ hadoop dfs -ls
Found 2 items
drwxr-xr-x   - hadoop supergroup          0 2013-07-28 12:57 /user/hadoop/apachelog
drwxr-xr-x   - hadoop supergroup          0 2013-07-28 13:42 /user/hadoop/apachelog.out
[hadoop@isis ~]$
[hadoop@isis ~]$ hadoop dfs -ls apachelog.out

Found 3 items
-rw-r--r--   1 hadoop supergroup          0 2013-07-28 13:42 /user/hadoop/apachelog.out/_SUCCESS
drwxr-xr-x   - hadoop supergroup          0 2013-07-28 13:30 /user/hadoop/apachelog.out/_logs
-rw-r--r--   1 hadoop supergroup       1438 2013-07-28 13:40 /user/hadoop/apachelog.out/part-00000
[hadoop@isis ~]$
[hadoop@isis ~]$ hadoop dfs -cat apachelog.out/part-00000

127.0.0.1       567
192.168.100.106 327
192.168.100.107 671
192.168.100.109 2
192.168.100.150 193

[hadoop@isis ~]$

以上

 

No tags for this post.

コード、エラー、設定ファイル共有サイトのすすめ

Pocket

 

sprunge.usというサービスがあるのを、いまさら知って驚いてそして大感謝した。
以下に顛末を記す。

sprunge.usってなんだ。

ブラウザでsprunge.usを開くと、manページのような見てくれで何か間違えたかと二度見するようなサイトなのだが、よく見ると凄い事が書いてある。

何らかのコマンドの標準出力をsprunge.usに食わすと、URLが返る。
そのURLへアクセスすると、先の出力結果が見えるというわけ。

sprunge.usの使い方

使い方といっても上記の通りなんだが、やってみるのが早い。
uname -aの結果を食べさせてみる。

$ uname -a | curl -F 'sprunge=<-' http://sprunge.us
http://sprunge.us/CTQL

返ってきたURL、http://sprunge.us/CTQLにアクセスしていただくと、uname -aの結果、すなわち我輩の鯖の詳細が分かる。

 

使いどころ

このサービスの何が便利なのか。
sprunge.usを使うことで、エラーや設定ファイル、ちょっとしたスクリプト、ソースを手軽に共有できる。

たとえば私が、あるサーバが意図した動作をせず困っているときに、助けを求めるとする。
助けを求める相手が、twitterにいるとする。
twitterには140文字しか書けないので、エラー、使用している設定ファイルの中身をすべて貼り付けるのは無理がある。
ではどこかのサイト(いわゆるアップローダと言われているサイトなど)にアップロードするか?それも面倒。
そこでコマンドラインからsprunge.usにアップロードし、そのURLを相手に送る。

これは便利じゃありませんかみなさん。
まあ、助けを求める相手がいる限りにおいてですが。

 

いつまで残るの・・・?

sprungeに載せた内容はいつまで残るのか。
調べてみたけど、ちょっと分からなかった。
末尾で触れるpastebinだと、残す期間を選べたりするのだが。

 

やってもうた時は?

共有すべきでない内容をsprunge.usしてしまった時はどうするのだろうか。
これも検索したけど分からない。
センシティブな情報、IDとかパスワードとかが含まれそうな場合は、後述のpastbinの方がよいかも。

 

sprungeをもっと便利に使う。

まずですね、aliasを設定しましょう。
こんな長いの、いちいちタイプできんですよ。
設定したらすぐ確かめるのが紳士のたしなみ。ここだとaliasを引数なしですぐさま叩く。

$ alias sprunge="curl -F 'sprunge=<-' http://sprunge.us"
$ alias
alias sprunge='curl -F '\''sprunge=<-'\'' http://sprunge.us'

テストして問題なければ、シェルに合わせた初期設定ファイルに書き込んでおく。
~/.profileとか。

sprungeはファイルの内容だってOK。

sprungeは標準出力を受け付けるので、ファイルの内容だって貼り付けられる。
FreeBSDのftpd起動シェルスクリプトで試してみよう。
どうせなら、上記で作成したaliasで。

$ cat /etc/rc.d/ftpd | sprunge
http://sprunge.us/LQCZ

http://sprunge.us/LQCZ どうだろうか。

 

構文強調と行番号表示もできる。

sprunge.usに以下のように書いてある。

    add ?<lang> to resulting url for line numbers and syntax highlighting
    use this form to paste from a browser

上記のftpdシェルスクリプトを例に引く。
シェルスクリプトなので、「sh」を?に続けてURLに加えればよい。

http://sprunge.us/LQCZ?sh

 

sprungeに意地悪をしてみる。

知る人ぞ知るコマンドにslがある。

これはlsをslとタイプミスしてしまったとき、アスキーアートのSL機関車がターミナルを爆走する豪快なコマンドだ。
slコマンドをご存じなく、UNIX系マシンをお持ちの方はぜひインストールしてその目で確かめてほしい。
ちなみにFreeBSDではportsに収録されている。games/slからどうぞ。

で、これをsprungeに食わせてみた。

$ sl | sprunge
http://sprunge.us/Sijg

http://sprunge.us/Sijg …うん。まあ。仕方ないね。

 

同様の別サービス

sprunge.usと同様のサービスにpastbinがある。
http://pastebin.com/
世間的にはsprunge.usよりこちらの方が有名な様子。

CUIから使うためにwgetpastといったツールもある。

 

 

No tags for this post.

[Hadoop]擬似分散モードで実験

Pocket

 

擬似分散モードで実験してみる。
Hadoopには、単語を数えるデモが付いてくるのでこれを使う。

カウント対象テキストの準備

以下のようなファイルを作る。

[hadoop@isis ~/sandbox/input]$ ls
test.txt
[hadoop@isis ~/sandbox]$ cat ./input/test.txt
aa
bb
cc
aa
bb

 

ファイルのHDFSへの格納

上で作ったファイルをHDFSに置く。
こういったファイル操作は、hadoopコマンドにdfsを付けて、-putとか-lsとか叩く。
hadoop dfsとやれば使用できるコマンドの一覧が表示される。-catとか-rmとかも使える。ディレクトリの削除は-rmr。

下記の例では、カレントディレクトリにあるinputディレクトリを、HDFSのinputディレクトリに-putでコピーしている。
inputディレクトリには、先に作ったtest.txtが入っている。

[hadoop@isis ~/sandbox]$ hadoop dfs -put input input
[hadoop@isis ~/sandbox]$
[hadoop@isis ~/sandbox]$ hadoop dfs -ls
Found 1 items
drwxr-xr-x   - hadoop supergroup          0 2013-07-27 23:51 /user/hadoop/input
[hadoop@isis ~/sandbox]$
[hadoop@isis ~/sandbox]$ hadoop dfs -ls input
Found 1 items
-rw-r--r--   1 hadoop supergroup         15 2013-07-27 23:51 /user/hadoop/input/test.txt

送り先には絶対パスを付けなくても自動的に/usr/hadoopの下になっていることが分かる。
すなわち、~/sandboxにいるときに、送り元、送り先双方にinputを指定すると、ローカルの~/hadoop/sandbox/inputが、HDFS上の/usr/hadoop/inputにコピーされる。

 

wordcountの実行

hadoop-examples-1.0.0.jarにwordcountと続け、カウント対象のファイルが置かれるディレクトリ、カウント結果のファイルが置かれるディレクトリを指定する。
下記の例では先にコピーしたinputを、結果をoutputとして指定する。
outputはこの時点では無くてOK。
「outputがすでにあるよ」と言われたら中身を確認してからhadoop dfs -rmr outputなどとして消す。

hadoopの実行は何かとコマンドが長くなりがちなので、\を使って見やすく複数行にしたほうがよいでしょう。

[hadoop@isis ~/sandbox]$ hadoop jar \
/usr/local/share/examples/hadoop/hadoop-examples-1.0.0.jar \
wordcount input output

13/07/28 00:02:27 INFO input.FileInputFormat: Total input paths to process : 1
13/07/28 00:02:45 INFO mapred.JobClient: Running job: job_201307272333_0001
13/07/28 00:02:46 INFO mapred.JobClient:  map 0% reduce 0%
13/07/28 00:06:44 INFO mapred.JobClient:  map 100% reduce 0%
13/07/28 00:08:01 INFO mapred.JobClient:  map 100% reduce 66%
13/07/28 00:08:11 INFO mapred.JobClient:  map 100% reduce 100%
13/07/28 00:09:15 INFO mapred.JobClient: Job complete: job_201307272333_0001
13/07/28 00:09:26 INFO mapred.JobClient: Counters: 26
13/07/28 00:09:26 INFO mapred.JobClient:   Job Counters
13/07/28 00:09:26 INFO mapred.JobClient:     Launched reduce tasks=1
13/07/28 00:09:26 INFO mapred.JobClient:     SLOTS_MILLIS_MAPS=159745
13/07/28 00:09:26 INFO mapred.JobClient:     Total time spent by all reduces waiting after reserving slots (ms)=0
13/07/28 00:09:26 INFO mapred.JobClient:     Total time spent by all maps waiting after reserving slots (ms)=0
13/07/28 00:09:26 INFO mapred.JobClient:     Launched map tasks=1
13/07/28 00:09:26 INFO mapred.JobClient:     Data-local map tasks=1
13/07/28 00:09:26 INFO mapred.JobClient:     SLOTS_MILLIS_REDUCES=66457
13/07/28 00:09:26 INFO mapred.JobClient:   File Output Format Counters
13/07/28 00:09:26 INFO mapred.JobClient:     Bytes Written=15
13/07/28 00:09:26 INFO mapred.JobClient:   FileSystemCounters
13/07/28 00:09:26 INFO mapred.JobClient:     FILE_BYTES_READ=33
13/07/28 00:09:26 INFO mapred.JobClient:     HDFS_BYTES_READ=123
13/07/28 00:09:26 INFO mapred.JobClient:     FILE_BYTES_WRITTEN=43099
13/07/28 00:09:26 INFO mapred.JobClient:     HDFS_BYTES_WRITTEN=15
13/07/28 00:09:26 INFO mapred.JobClient:   File Input Format Counters
13/07/28 00:09:26 INFO mapred.JobClient:     Bytes Read=15
13/07/28 00:09:26 INFO mapred.JobClient:   Map-Reduce Framework
13/07/28 00:09:26 INFO mapred.JobClient:     Map output materialized bytes=33
13/07/28 00:09:26 INFO mapred.JobClient:     Map input records=5
13/07/28 00:09:26 INFO mapred.JobClient:     Reduce shuffle bytes=0
13/07/28 00:09:26 INFO mapred.JobClient:     Spilled Records=6
13/07/28 00:09:26 INFO mapred.JobClient:     Map output bytes=35
13/07/28 00:09:26 INFO mapred.JobClient:     Total committed heap usage (bytes)=209518592
13/07/28 00:09:26 INFO mapred.JobClient:     Combine input records=5
13/07/28 00:09:26 INFO mapred.JobClient:     SPLIT_RAW_BYTES=108
13/07/28 00:09:26 INFO mapred.JobClient:     Reduce input records=3
13/07/28 00:09:26 INFO mapred.JobClient:     Reduce input groups=3
13/07/28 00:09:26 INFO mapred.JobClient:     Combine output records=3
13/07/28 00:09:26 INFO mapred.JobClient:     Reduce output records=3
13/07/28 00:09:26 INFO mapred.JobClient:     Map output records=5
[hadoop@isis ~/sandbox]$

仮想環境上とはいえ7分てどういうこと。

結果の確認

結果は。指定したディレクトリ、outputに格納される。
outputの中身を見ると、処理の成功したことを示す_SUCCESSというファイルに、結果の書き込まれるpart-r-00000が格納されている。
hadoop dfs -catで中身を確認すると、各単語の数がリストされている。

[hadoop@isis ~/sandbox]$ hadoop dfs -ls

Found 2 items
drwxr-xr-x   - hadoop supergroup          0 2013-07-27 23:51 /user/hadoop/input
drwxr-xr-x   - hadoop supergroup          0 2013-07-28 00:08 /user/hadoop/output
[hadoop@isis ~/sandbox]$ hadoop dfs -ls output
Warning: $HADOOP_HOME is deprecated.

Found 3 items
-rw-r--r--   1 hadoop supergroup          0 2013-07-28 00:08 /user/hadoop/output/_SUCCESS
drwxr-xr-x   - hadoop supergroup          0 2013-07-28 00:02 /user/hadoop/output/_logs
-rw-r--r--   1 hadoop supergroup         15 2013-07-28 00:08 /user/hadoop/output/part-r-00000
[hadoop@isis ~/sandbox]$
[hadoop@isis ~/sandbox]$ hadoop dfs -cat output/part-r-00000
aa      2
bb      2
cc      1
[hadoop@isis ~/sandbox]$

これだけのために7分とは。
実マシン、かつもっともっと大きなログで試してみたいところ。

 

関連エントリ

[FreeBSD] Hadoopのportsからのインストール
[FreeBSD] portsのHadoopで分散(x-distributed)モードを動かす準備
[Hadoop]Hadoop 擬似分散(Psuedo-distributed)モードの設定
[Hadoop] 擬似分散モードから完全分散モードへ(データノードの追加)


No tags for this post.

[Hadoop]Hadoop 擬似分散(Psuedo-distributed)モードの設定

Pocket

 

Standaloneモードでは、複数のホストを使った処理は行わない。デーモンも動かさない。

しかしHadoopは分散処理をしてナンボである。
分散処理をする場合には、複数のホストでいくつかのデーモンを動作させる必要がある。
それはまあ当然。

ただ、いきなり複数ホストを使うのはハードルが高い。
そこで、「Hadoopは複数ホストで動いているつもりだけど実際は1台のホストで動いている」モードで設定の確認をする。
これが擬似分散(Psuedo-distributed)モード。

擬似分散モードに必要な各設定の意味

擬似分散(Psuedo-distributed)モードの動作には以下、四つの設定が必要。
完全分散(Full distributed)モードでも変わらないんだけどね。

  1. HDFSのメタデータを格納するnamenodeの設定
  2. データをいくつ複製(replication)するかの設定(デフォルトで3)
  3. タスク分散を受け持つJobTrackerの設定
  4. 実データを格納し、タスクを実行するdatanodeかつTaskTrackerの設定

1と3と4にそれぞれlocalhostを指定する(なおこれを別ホストにすればFull distributedモードに)。
2では1を指定する。
デフォルトのままだと、複製を3つ作ろうとする。ひいてはホストが3つ必要になってしまう。
擬似分散モードでは自ホストしか使わないわけだから1を指定するというわけ。

namenode, replication, JobTrackerの設定

以下、三つのファイルを変更する。
前章の1,2,3に対応する。

  • core-site.xml(namenode設定)
  • hdfs-site.xml(replication設定)
  • mapred-site.xml(JobTracker設定)

FreeBSDでportsから入れたなら/usr/local/etc/hadoopにある。

core-site.xml

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

hdfs-site.xml

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

mapred-site.xml

<configuration>
        <property>
                <name>mapred.job.tracker</name>
                <value>localhost:8021</value>
        </property>
</configuration>

 

datanode, TaskTrackerの設定

/usr/local/etc/hadoopの下にmasters, slavesというファイルを作る。
ここでsecondary namenode, datanode, TaskTrackerを指定する。

secondary namenodeとは、namenodeのデータをバックアップするノード。
datanode、TaskTrackerとは、HDFSの実データが置かれ、JobTrackerから指定されたタスクをこなすノード。

mastersというファイルには、secondary namenodeを書く。
slavesというファイルには、datanodeかつTaskTrackerとなるホストを書く。

擬似分散モードでは、secondary namenodeの指定は不要。
mastersという空ファイルだけ作っておけばよい。
slavesには、localhostと書いておく。

$ cd /usr/local/etc/hadoop/
$ sudo touch slaves masters
$ sudo sh -c 'echo "localhost" >> ./slaves'
$ cat masters
$
$ cat slaves
localhost
$

 

HDFSのフォーマット

初回に限り、HDFSのフォーマットが必要である。
HDFSにはメタデータを保存するnamenodeと、実データの保存されるdatanodeがある。

ここでの「HDFSのフォーマット」とは、実際のところnamenodeの初期化を意味する。

なので、datanodeはこのフォーマットとは無関係。不要。
しかもdatanodeを追加したり削除したときだって、namenodeでの設定変更、フォーマットは不要。

拍子抜けするくらいである。
だが。裏を返すとnamenodeが壊れればすべてのデータが死亡することを意味する。
実運用の際には、secondaly namenodeを立てるなどして事故に備えることになる。

しかし今は擬似分散モードなので気軽に進める。
HDFSのフォーマットは以下のようにして行う。
※フォーマットは、実際にHadoopを使うユーザで行うこと。FreeBSDでportsから入れた場合は注意

$ hadoop namenode -format
Warning: $HADOOP_HOME is deprecated.

13/07/23 20:12:16 INFO namenode.NameNode: STARTUP_MSG:
/************************************************************
STARTUP_MSG: Starting NameNode
STARTUP_MSG: host = localhost/127.0.0.1
STARTUP_MSG: args = [-format]
STARTUP_MSG: version = 1.0.0
STARTUP_MSG: build = https://svn.apache.org/repos/asf/hadoop/common/branches/branch-1.0 -r 1214675; compiled by 'hortonfo' on Thu Dec 15 16:36:35 UTC 2011
************************************************************/
13/07/23 20:12:18 INFO util.GSet: VM type = 64-bit
13/07/23 20:12:18 INFO util.GSet: 2% max memory = 19.33375 MB
13/07/23 20:12:18 INFO util.GSet: capacity = 2^21 = 2097152 entries
13/07/23 20:12:18 INFO util.GSet: recommended=2097152, actual=2097152
13/07/23 20:12:19 INFO namenode.FSNamesystem: fsOwner=vanilla
13/07/23 20:12:20 INFO namenode.FSNamesystem: supergroup=supergroup
13/07/23 20:12:20 INFO namenode.FSNamesystem: isPermissionEnabled=true
13/07/23 20:12:20 INFO namenode.FSNamesystem: dfs.block.invalidate.limit=100
13/07/23 20:12:20 INFO namenode.FSNamesystem: isAccessTokenEnabled=false accessKeyUpdateInterval=0 min(s), accessTokenLifetime=0 min(s)
13/07/23 20:12:20 INFO namenode.NameNode: Caching file names occuring more than 10 times
13/07/23 20:12:20 INFO common.Storage: Image file of size 113 saved in 0 seconds.
13/07/23 20:12:20 INFO common.Storage: Storage directory /tmp/hadoop-vanilla/dfs/name has been successfully formatted.
13/07/23 20:12:20 INFO namenode.NameNode: SHUTDOWN_MSG:
/************************************************************
SHUTDOWN_MSG: Shutting down NameNode at localhost/127.0.0.1
************************************************************/

 

HDFSの場所

上記のログにもある通り、デフォルトでは/tmpの下に作られる。
厳密に言えば、/tmp/hadoop-${user.name} に作られる。
namenodeでも、datanodeでも同じ。

/tmpディレクトリだと、システムが消したりするので実運用では場所を変えたほうがよい。

これらの場所は、hdfs-site.xmlで制御できる。
hadoop.tmp.dirがprefixなので、これを変えればよい。
あるいは、dfs.name.dir(namenode向け)、dfs.data.dir(datanode向け)で明示してもよい。

Hadoopの起動

start-all.shで起動させる。

$ sudo su - hadoop
[hadoop@isis ~]$
[hadoop@isis ~]$
[hadoop@isis ~]$ start-all.sh
Warning: $HADOOP_HOME is deprecated.

starting namenode, logging to /var/log/hadoop/hadoop-hadoop-namenode-isis.out
localhost: Warning: $HADOOP_HOME is deprecated.
localhost:
localhost: starting datanode, logging to /var/log/hadoop/hadoop-hadoop-datanode-isis.out
starting jobtracker, logging to /var/log/hadoop/hadoop-hadoop-jobtracker-isis.out
localhost: Warning: $HADOOP_HOME is deprecated.
localhost:
localhost: starting tasktracker, logging to /var/log/hadoop/hadoop-hadoop-tasktracker-isis.out
[hadoop@isis ~]$

HADOOP_HOMEについて文句をつけられている。スクリプトを見れば分かるが、これは無視してよい。この点については別途。
namenode, datanode, jobtracker, tasktrackerの4つを起動しようと試みていることが分かる。

さて実際に起動しているか。jpsで確認。動いていますな。

[hadoop@isis ~]$ jps
2135 DataNode
2324 TaskTracker
2057 NameNode
2377 Jps
2229 JobTracker
[hadoop@isis ~]$

 

そしてこれらのプロセスは、ポート待ち受けをする。調べてみる。

[hadoop@isis ~]$ sockstat -l4|grep hadoop
hadoop   java       1746  55 tcp4 6 *:24923               *:*
hadoop   java       1746  60 tcp4   127.0.0.1:8021        *:*
hadoop   java       1746  71 tcp4 6 *:50030               *:*
hadoop   java       1621  55 tcp4 6 *:64722               *:*
hadoop   java       1621  63 tcp4   127.0.0.1:8020        *:*
hadoop   java       1621  74 tcp4 6 *:50070               *:*
[hadoop@isis ~]$

50030はJobTrackerの、50070はnamenodeの管理Web用ポート、8020はnamenodeの、8021はdatanodeのポート。

namenodeに対し、ブラウザで前二者のポートにアクセスするとステータスが分かる。

実際に動かすのは今度。
関連エントリ

[FreeBSD] Hadoopのportsからのインストール
[FreeBSD] portsのHadoopで分散(x-distributed)モードを動かす準備
[Hadoop]擬似分散モードで実験
[Hadoop] 擬似分散モードから完全分散モードへ(データノードの追加)

No tags for this post.

[FreeBSD] portsのHadoopで分散(x-distributed)モードを動かす準備

Pocket

 

Hadoopを動かすには、いくつか環境変数の設定が必要である。
JAVA_HOMEとか、HADOOP_PREFIXとか。
また同時に、複数ノードの制御のために、sshやrsyncだって使う。

以上のことを考えると、専用のユーザを作っておくのが便利である。

ところで、Hadoopをportsから入れると、ユーザhadoopが作られる。
ユーザhadoopを使うのがよさそうだが、しかしこのユーザhadoopはそのままでは使えない。
シェルに/sbin/nologinが設定されているから。

Hadoopをportsからインストールしたとき、そういったことも併せて、擬似分散モード、完全分散モードで動かす準備をまとめる。
準備は大きく分けて二段階。ユーザhadoopの環境設定と、sshdの設定変更。

ユーザhadoopのホームディレクトリ、シェル情報の変更

vipwでhadoopの行を以下のように書き換える。

hadoop:*:955:955::0:0:hadoop user:/nonexistent:/usr/sbin/nologin
※以下のように書き換え
hadoop:*:955:955::0:0:hadoop user:/home/hadoop:/usr/local/bin/bash

 

パスワードは変えなくてもよい。
sudo su – hadoopしたらいいし、リモートから直接hadoopとしてログインしたい場合には鍵を使うから。

ユーザhadoopのホームディレクトリと.profileの作成

ホームディレクトリを作り、HADOOP関連の環境変数を.profileに書き込む。
追加でHADOOP_PREFIXという変数も加えておく。

$ sudo mkdir /home/hadoop
$ sudo sh -c 'cat /usr/local/etc/hadoop/envvars.d/* >> /home/hadoop/.profile'
$ sudo sh -c 'echo "PATH=$PATH:/usr/local/share/hadoop/bin;export PATH" >> /home/hadoop/.profile'
$ sudo sh -c 'echo "export HADOOP_PREFIX=/usr/local/share/hadoop" >> /home/hadoop/.profile'
$

 

上記の手順を踏むと、.profileの中身は以下のように。

$ cat /home/hadoop/.profile
export JAVA_HOME=${JAVA_HOME:-/usr/local/openjdk6}

export HADOOP_HOME=/usr/local/share/hadoop
export HADOOP_CONF_DIR=/usr/local/etc/hadoop
export HADOOP_LOG_DIR=/var/log/hadoop
export HADOOP_PID_DIR=/var/run/hadoop
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/games:/usr/local/sbin:/usr/local/bin:/home/doe/bin:/usr/local/share/hadoop/bin;export PATH
export HADOOP_PREFIX=/usr/local/share/hadoop

 

 

実際にログインして環境変数が設定されているか確認。
なってますな。

$ sudo su - hadoop
[hadoop@vanilla ~]$ env | egrep 'JAVA|HADOOP|PATH'
HADOOP_LOG_DIR=/var/log/hadoop
HADOOP_HOME=/usr/local/share/hadoop
HADOOP_PID_DIR=/var/run/hadoop
HADOOP_PREFIX=/usr/local/share/hadoop
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/games:/usr/local/sbin:/usr/local/bin:/home/hadoop/bin:/usr/local/share/hadoop/bin
JAVA_HOME=/usr/local/openjdk6
HADOOP_CONF_DIR=/usr/local/etc/hadoop

 

ユーザhadoopのssh設定。

これは複数ノードの制御のため。
ポイントは二つある。
・パスワードなしでssh接続できるようにしておく。
・リモート接続したときにも環境変数が有効になるようにしておく。

パスワードなしのssh接続。

鍵を作っておいて、パスワードなしでリモートノードに接続できるようにしておく。
(セキュリティ的にはおおらかですな。もちろんセキュリティ向上の取り組みはなされているようだけど)

これはもうお決まりの手順。

$ sudo su - hadoop
[hadoop@vanilla ~]$
[hadoop@vanilla ~]$ ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa
Generating public/private dsa key pair.
Created directory '/home/hadoop/.ssh'.
Your identification has been saved in /home/hadoop/.ssh/id_dsa.
Your public key has been saved in /home/hadoop/.ssh/id_dsa.pub.
The key fingerprint is:
bf:69:a7:7f:73:af:ed:2d:d7:02:5a:05:ce:08:a1:44 hadoop@isis
The key's randomart image is:
+--[ DSA 1024]----+
| .E .. |
| . .. . |
| . . + . |
| . o . |
| S . |
| . o |
| .o . .|
| oo. =.=|
| .++...O*|
+-----------------+
[hadoop@vanilla ~]$
[hadoop@vanilla ~]$ cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized_keys
[hadoop@vanilla ~]$
[hadoop@vanilla ~]$ ssh localhost
The authenticity of host 'localhost (127.0.0.1)' can't be established.
ECDSA key fingerprint is fc:b3:5c:28:1f:2f:32:21:0a:ba:1c:51:00:95:47:7a.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'localhost' (ECDSA) to the list of known hosts.
FreeBSD 9.1-RELEASE-p4 (GENERIC) #0: Mon Jun 17 11:42:37 UTC 2013

Welcome to FreeBSD!

いったん抜ける

リモート制御(コマンド実行)のためのssh設定

ここでまとめた通り、~/.ssh/environment環境変数の記載をする。
$PATHとかの表記をしない。exportも省く。

[hadoop@vanilla ~]$ cat ~hadoop/.ssh/environment
JAVA_HOME=/usr/local/openjdk6
HADOOP_HOME=/usr/local/share/hadoop
HADOOP_CONF_DIR=/usr/local/etc/hadoop
HADOOP_LOG_DIR=/var/log/hadoop
HADOOP_PID_DIR=/var/run/hadoop
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/games:/usr/local/sbin:/usr/local/bin:/home/doe/bin:/usr/local/share/hadoop/bin
HADOOP_PREFIX=/usr/local/share/hadoop

 

リモート制御(コマンド実行)のためのssh「d」設定

おなじく、sshdの設定を変える。

$ sudo cp /etc/ssh/sshd_config{,.org}
$ sudo vi /etc/ssh/sshd_config
※以下のように書き換え
#PermitUserEnvironment no
PermitUserEnvironment yes

$ sudo service sshd restart
Stopping sshd.
Starting sshd.
$

 

確認。
パスワードなしでログインできて、環境変数もOK.

$ sudo su - hadoop
[hadoop@vanilla ~]$
[hadoop@vanilla ~]$ ssh localhost env | egrep 'JAVA|HADOOP|PATH'
HADOOP_LOG_DIR=/var/log/hadoop
HADOOP_HOME=/usr/local/share/hadoop
HADOOP_PID_DIR=/var/run/hadoop
HADOOP_PREFIX=/usr/local/share/hadoop
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/games:/usr/local/sbin:/usr/local/bin:/home/hadoop/bin:/usr/local/share/hadoop/bin
JAVA_HOME=/usr/local/openjdk6
HADOOP_CONF_DIR=/usr/local/etc/hadoop
[hadoop@vanilla ~]$

 

以上

関連エントリ。

[FreeBSD] Hadoopのportsからのインストール
[Hadoop]Hadoop 擬似分散(Psuedo-distributed)モードの設定
[Hadoop]擬似分散モードで実験
[Hadoop] 擬似分散モードから完全分散モードへ(データノードの追加)

No tags for this post.

[FreeBSD][Linux] ssh経由でコマンド実行すると環境変数を読まないでござる

Pocket

ssh経由bashでコマンド実行するときの環境変数を有効にするには。

以下のようにして、リモートホストでコマンドを実行する場合、リモートでの環境変数が有効にならない事がある。

$ ssh user@remotehost /path/command

 

これはbashの仕様が原因で、解決にはsshdとリモートユーザの設定が必要。
おそらくshでも同じと思うが、ひとくちにshと言ってもいろんな変種があるので調べていない。
以下にまとめる。

なお、複数ホストを用意するのが面倒なので、本記事で実例を示す場合には接続先をlocalhostしている。

Continue reading

No tags for this post.

[FreeBSD] Hadoopのportsからのインストール

Pocket

 

Hadoopをインストールしたのでメモ。

 

野良HadoopとportsのHadoop

Hadoopを野良で入れるか、portsから入れるか。
結局portsにした。その訳は。

hadoopはJavaで動作する。
ということは、Javaさえ入っていれば、インストールに特殊な手間の必要なくhadoopが動作するはず。
だからインストールを扱う記事、blog等々はhadoopをダウンロードしてtarで展開して…、というものがほとんど。
FreeBSDでだってそれは同じ。

しかしFreeBSDでは、hadoopがportsに収録されている。
portsだと依存するportsを一括で入れてくれるし、ユーザ追加や権限設定なども自動でしてくれる。
便利な一方、世の中の記事とは違うところ(おもにファイル配置)が出てきたり、ひょっとすると最新版を使えないリスクもある。

どっちもどっちだが、hadoopが初めてならportsから入れるのが良いと判断した。
Javaなど依存portsのインストールが面倒だし、そもそもやりたいことはHadoopのセットアップではなくてその先にあるわけだから。
なお2013/7/23時点でportsのhadoopは1.0.0の模様。

 

hadoopのインストール

ports、と言っておきながらなんだけど、けっこう量があるのでスピード重視でpackageから入れた。

まずpackageの入手先を近所のftpに設定する。~/.profileに書いとけ。

PACKAGEROOT="ftp://ftp2.jp.freebsd.org";export PACKAGEROOT

 

sudoを使うならvisudoで以下の行をアンコメントしておく。

Defaults env_keep += "PKG_PATH PKG_DBDIR PKG_TMPDIR TMPDIR PACKAGEROOT PACKAGESITE PKGDIR FTP_PASSIVE_MODE"

 

インストール。あそうそう、bashとrsyncも忘れずにね。

$ sudo pkg_add -r bash rsync hadoop

 

しばらく放置。

 

事前準備

一式が入ったのだが、hadoopを動かす前に準備がいる。
OpenJDK向け設定、ホスト名の設定、JAVA_HOMEの設定。

 

OpenJDK向けの設定

OpenJDKをインストールすると以下の表示が現れる。
素直に設定する。

===============================================================
This OpenJDK implementation requires fdescfs(5) mounted on /dev/fd and
procfs(5) mounted on /proc.

If you have not done it yet, please do the following:

mount -t fdescfs fdesc /dev/fd
mount -t procfs proc /proc

To make it permanent, you need the following lines in /etc/fstab:

fdesc /dev/fd fdescfs rw 0 0
proc /proc procfs rw 0 0

===============================================================

 

以下のように。

$ sudo mount -t fdescfs fdesc /dev/fd
$ sudo mount -t procfs proc /proc
$ mount
/dev/da0p2 on / (ufs, local, journaled soft-updates)
devfs on /dev (devfs, local, multilabel)
fdescfs on /dev/fd (fdescfs)
procfs on /proc (procfs, local)

 

/etc/fstabにも以下の通り記載しておく(空白はタブで)

fdesc /dev/fd fdescfs rw 0 0
proc /proc procfs rw 0 0

 

ホスト名の設定

hadoopはhostnameが解決できないと動作しない。
/etc/hostsにhostnameの記載があるか確認して、なければ加える。
DHCPでIPアドレス取得しているなら、127.0.0.1のところにホスト名を入れる。
以下はhostnameがvanillaの場合

127.0.0.1 localhost localhost.my.domain vanilla

 

JAVA_HOMEの設定

portsからHadoopをインストールしているなら不要。
/usr/local/etc/hadoop/envvars.d/000.java_home.envでJAVA_HOMEを設定している。
そして000.java_home.envは起動の都度、読み込まれる(後述)。

export JAVA_HOME=${JAVA_HOME:-/usr/local/openjdk6}

 

portsから入れていないんだったら、hadoopを使うユーザの~/.profileで設定しておく。

JAVA_HOME=/usr/local/openjdk6;export JAVA_HOME

 

 

ファイル配置

ファイル配置の確認。
portsから入れると、FreeBSDの流儀に沿ってファイルが配置される。

openjdk6の場所

/usr/local/openjdk6

 

hadoop関連

hadoopコマンド: /usr/local/bin/hadoop
実行ファイル他: /usr/local/share/hadoop
設定: /usr/local/etc/hadoop
ログ: /var/log/hadoop
設定サンプル: /usr/local/share/examples/hadoop/

 

各ディレクトリの中身

openjdk6

$ ls /usr/local/openjdk6/
ASSEMBLY_EXCEPTION demo man
LICENSE include sample
THIRD_PARTY_README jre src.zip bin lib

 

hadoop関連ファイル

$ ls /usr/local/etc/hadoop
capacity-scheduler.xml hadoop-policy.xml
configuration.xsl hdfs-site.xml
core-site.xml log4j.properties
envvars.d mapred-queue-acls.xml
fair-scheduler.xml mapred-site.xml
hadoop-env.sh taskcontroller.cfg
hadoop-metrics2.properties

$ ls /usr/local/share/hadoop/
bin hadoop-core-1.0.0.jar lib
contrib hadoop-test-1.0.0.jar webapps
hadoop-ant-1.0.0.jar hadoop-tools-1.0.0.jar

$ ls /usr/local/share/examples/hadoop/
conf hdfs-default.xml
core-default.xml mapred-default.xml
hadoop-examples-1.0.0.jar

 

これでインストールはおしまい。
hadoopはこれだけでも動く。しかしその前に。

/usr/local/bin/hadoopってなんだ

FreeBSDのports特有のものと思うけど、/usr/local/bin/hadoopについて。

/usr/local/bin/hadoopを便宜的にhadoopコマンドと呼ぶ。
hadoop一式は/usr/local/share/hadoop下にあるのに一体これはなんだろう。

中身を見ればすぐ分かる。hadoopコマンドの正体はbashスクリプト。
もう少し見ると、環境変数を設定してからhadoopの実体を呼ぶwrapperであると分かる。
と同時に、環境変数の設定は/usr/local/etc/hadoop/envvars.dの下に置いておけばよいと言う点も分かる。

#!/usr/bin/env bash
for i in `ls /usr/local/etc/hadoop/envvars.d/*.env`
do
. ${i}
done

exec /usr/local/share/hadoop/bin/hadoop $@

続き

[FreeBSD] portsのHadoopで分散(x-distributed)モードを動かす準備
[Hadoop]Hadoop 擬似分散(Psuedo-distributed)モードの設定
[Hadoop]擬似分散モードで実験
[Hadoop] 擬似分散モードから完全分散モードへ(データノードの追加)

 

 


No tags for this post.

PDFをKindle PaperWhiteで読みやすく

Pocket

PDFをKindle PaperWhiteで読もうとすると、字が小さくなるうえにアンチエイリアスがかかってモヤっとした表示になり読みにくいことこの上ない。

そこでk2optpdfを使ってみた。
結論。
k2optpdfはやめて、横画面モード(Landscape Mode)にして読んでる。

k2optpdfとは

http://www.willus.com/k2pdfopt/
PDFを読みたい端末の解像度、画面サイズに合わせて表示を最適化してくれるツール。
なおここでのPDFとは、テキストデータが埋め込まれているものであって、画像データのPDF、要するに自炊PDFは対象外(のはず)

アウトプットのイメージは上記サイトの通り。

入手方法
http://www.willus.com/k2pdfopt/download/
ここで、左側のCapchaに数字を入れてから、使用しているコンピュータに対応したバージョンをダウンロードする。
スタンドアロンのプログラムなので、ダウンロードしたらそのまま使える。

使い方

http://www.willus.com/k2pdfopt/help/
ダウンロードしたファイルに、変換したいPDFをドラッグアンドドロップし、上記URLを参考に選択肢を選ぶだけ。
Windowsだとコマンドプロンプトが開いてメニューが表示される。

そこで変換先デバイスを選ぶ。dを押してから4を押す。
そしてもう一回Enterを押せばOK。

微妙な調整

上記で普通は問題ないはずだが、それでも変換結果に納得いかない場合がある。
以下にその例と対策を示す。

やっぱり字が小さい

-odpiでdpiを変更できる。-odpi 250くらいでどうか。

途中で落ちる

どうやら、ちょっと気合の入った段組みになったページはうまく変換できず落ちてしまうようだ。
面倒この上ないが、そういう場合は落ちたページを覚えておいて、以下のようにしてそのページを変換対象外にする。

k2pdfoptが落ちてしまうp3以外を変換する。
1-2, 4-

しかし最初から最後まで落ちまくる本もある。
例えばオライリーのheadfirstシリーズとか。
そういうのはもう諦めるしかない。

やっぱり微妙…。

そうしてこうして頑張って変換したけど、やっぱり使いにくい。
その理由を以下に列挙

  • 所詮は自動変換。段組みによって無茶苦茶な変換をする。
  • 変換したら格段にファイルサイズが増える。(画像データになるから)
  • テキストを選択できない。(画像データになるから。 native PDFオプションもあるにはあるが)
  • 落ちまくる。ストレス。

 

最終的に

冒頭で書いたとおり、そのままPDFを横画面モードで読んでます。

 

 

No tags for this post.