Technofara

Golangエンジニア!仕事で必要になって勉強した事とか、新しい事とか色々まとめたりを緩くやります。技術系と思考系だけにしておきます、

Elastic MapReduceを使って、FluentdでS3上に格納した、Ltsv形式のNginxのアクセスログを解析してみたお話。

今回何故、Elastic MapReduce + S3 + Fluentd + nginxを調査したのか

Mysqlとか、analyticsとか、そのほかで色々データは取っていってるのですが、 更に細かく解析するためには、ログレベルでの解析も必要になってくると思い調査し始めたのがきっかけです。 調べてみると、Redshift、Big Query、TreasureDataなど色々あるんですね、
でも今回は、Facebookで流れてきた記事に目がとまったので、まずはとElastic MapReduceの調査をしてみました。
構成としては、Elastic MapReduce + S3 + Fluentd + nginxでやってみます。

Nginxで書きだしたltsv形式のログが、fluentdでS3に転送されています

AWS上で準備(Elastic MapReduce Job Flows作成)

新しいJOBを作成する

f:id:shinofara:20130914235100p:plain

JOBの名前とか、versionとか、スクリプト選択

f:id:shinofara:20130914235104p:plain

今回は、hiveを選択します。

hive sessionを選択

Start an Interactive Hive Session

マスターinstance、core instanceの台数、グレードなどなどを選択

f:id:shinofara:20130914235106p:plain

今回は確認なので、smallで、1台1台にしました。

キーペア、ログ出力先などなど

f:id:shinofara:20130914235109p:plain

sshでアクセスする際のキーペアとか ログ出力先を設定します。

Bootstarap action

Proceed with no Bootstrap Actions

最後は確認して作成

f:id:shinofara:20130914235112p:plain

これで、AWS側での準備は完了です!!

では、実戦してみます。

準備や、今回の調査時の環境について

ログを格納しているS3ですが、 <バケット名>/nginx.access/XXXXXXX/2013/09/09/ログファイル この様に、なっています。 XXXXには、サーバHOST名、年、月、日という感じです。

そしてログファイルは、Ltsvで出力されたファイルです。 ltsv形式のデータの一行抜粋するとこんな感じ(データの一部を当てで変更しています)

2013-09-13T00:00:03+09:00 nginx.access/XXXXXXX    {"host":"999.99.99.999","forwardedfor":"999.99.99.999, 182.161.76.45","method":"GET","path":"/","status":"200","size":"20444","referer":"-","ua":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) 

とりあえず、ログイン

$ ssh -i ~/KEY hadoop@ec2-99-999-999-999.ap-northeast-1.compute.amazonaws.com

EC2で使い慣れた、「ec2_user」では無く、「hadoop」ユーザを使用します。

hiveを起動

$ hive
hive> 

Fluentdで回収したログのデータを格納するhive上のtableをつくります。

CREATE EXTERNAL TABLE IF NOT EXISTS fluentLog (dt string, tag string, json string)
PARTITIONED BY ( PT STRING )
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' LINES TERMINATED BY '\n';
OK

dt string, tag string, json stringがポイントです
ltsvをfluentdで回収すると
日付<タブ>タグ<タブ>JSONデータの形式ですので、それを格納するように定義してます。

次はデータをごにょごにょ

hive>  ALTER TABLE fluentLog ADD PARTITION ( pt='2013-09-09' ) LOCATION 's3://<バケット名>/nginx.access/XXXXXXX/2013/09/09'; 
OK
Time taken: 5.252 seconds
 
hive>  ALTER TABLE fluentLog ADD PARTITION ( pt='2013-09-10' ) LOCATION 's3://<バケット名>/nginx.access/XXXXXXX/2013/09/10'; 
OK
Time taken: 5.252 seconds 

日付単位でpartition作成してます。

解析後のデータ格納用tableを作る!

今回は、簡単にステータスコードが何回登場したかという簡単な事をやってみます。

hive> CREATE EXTERNAL TABLE IF NOT EXISTS archiveLog (status int, cnt int)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' LINES TERMINATED BY '\n'
LOCATION 's3://<バケット名>/archives/${DATE}';
OK
Time taken: 0.197 seconds 

その為、status(int)とcnt(int)の二つを用意しました。 s3://<バケット名>/archives/${DATE}'は用意する必要ありません、処理実行後に作成されます。 解析後のデータがここに格納されるようです。

ついに処理を実行する時が.....

INSERT OVERWRITE TABLE  archiveLog
SELECT
  status, count(*) as cnt
FROM
  fluentLog LATERAL VIEW
    json_tuple(fluentLog.json,  'ua', 'status') j
      AS ua,status
WHERE pt >='2013-09-09'
GROUP BY status;

2013-09-09と、2013-09-10以下のファイルすべてを対象に、statusとその回数を取得 そして、先ほど作成したtableに格納するという処理を行っています。

見た感じ、SQLライクに掛けるというのが、hiveのいいところですね

上のコマンドを実行したら

Total MapReduce jobs = 1
Launching Job 1 out of 1
Number of reduce tasks not specified. Estimated from input data size: 1
In order to change the average load for a reducer (in bytes):
...

どんどん文字が出力されます

2013-09-14 06:24:57,961 Stage-1 map = 0%,  reduce = 0%
2013-09-14 06:25:16,420 Stage-1 map = 1%,  reduce = 0%, Cumulative CPU 10.2 sec
2013-09-14 06:25:17,433 Stage-1 map = 1%,  reduce = 0%, Cumulative CPU 10.2 sec
2013-09-14 06:25:18,451 Stage-1 map = 1%,  reduce = 0%, Cumulative CPU 10.2 sec
2013-09-14 06:25:19,487 Stage-1 map = 1%,  reduce = 0%, Cumulative CPU 10.68 sec
2013-09-14 06:25:20,514 Stage-1 map = 1%,  reduce = 0%, Cumulative CPU 10.68 sec
2013-09-14 06:25:21,529 Stage-1 map = 1%,  reduce = 0%, Cumulative CPU 10.68 sec
2013-09-14 06:25:22,540 Stage-1 map = 2%,  reduce = 0%, Cumulative CPU 11.08 sec

をmap処理が少しずつ始まったようだ

2013-09-14 06:26:10,262 Stage-1 map = 8%,  reduce = 0%, Cumulative CPU 20.52 sec
2013-09-14 06:26:11,273 Stage-1 map = 8%,  reduce = 2%, Cumulative CPU 21.18 sec
2013-09-14 06:26:12,284 Stage-1 map = 8%,  reduce = 2%, Cumulative CPU 21.18 sec
2013-09-14 06:26:13,301 Stage-1 map = 8%,  reduce = 2%, Cumulative CPU 21.18 sec
2013-09-14 06:26:14,315 Stage-1 map = 9%,  reduce = 2%, Cumulative CPU 21.91 sec

Reduceも始まったようだ

マスター1台、ノード1台で確認しているので速度はあれみたい

2013-09-14 06:38:31,627 Stage-1 map = 100%,  reduce = 100%, Cumulative CPU 208.05 sec
2013-09-14 06:38:32,636 Stage-1 map = 100%,  reduce = 100%, Cumulative CPU 208.05 sec
MapReduce Total cumulative CPU time: 3 minutes 28 seconds 50 msec

少なめのデータで確認したとはいえ、3分半かかりました。むしろ3分半でおわりました?

どんな結果か確認してみます

解析後のデータは、s3://<バケット名>/archives/${DATE}'以下に格納されます。 恐る恐るひらいてみると

200     116080
302     2148
400     44
404     40
500     5

なるほど、なるほど

後始末

DROP TABLE fluentLog;
DROP TABLE archiveLog;

いらないので消しました。

簡単な調査を終えて

思った事

nginxのログ解析とかは、ltsv形式で出力、Fluentdで回収してS3へ転送する という設定ができていれば、容易に解析処理を行えるなと思いました! hiveのクエリを勉強する必要はありますが。

アプリケーションログに関しては、まだまだ調査できていないのでなんとも言えませんので コレに関しては、調査してからまたまとめてみよう。 そしてやっていけそうなら、本番でつかう

最後に一言

おもしろい