ApacheのアクセスログをAmazon Athenaを使って分析する

先日行われたre:Invent 2016で発表されたAmazon Athenaを利用して、Apache HTTP Serverのアクセスログを解析するまでの手順を紹介します。

Athenaで検索するためには、ログファイルをAmazon S3に配置しておく必要があります。LinuxからS3への転送にはfluentd(td-agent)を利用しました。

やりたいこと

Amazon Athenaを利用して、Apacheアクセスログ(combined log)に対しての検索クエリを実行できるようになりたい

前提環境

  • LinuxはAmazon EC2のRedHat Enterprise Linux 7.3 AMIから起動
  • EC2には、S3にPutObjectできる権限を持ったIAM Roleを紐付けておく
  • Amazon Athenaはus-west-2(Oregon)リージョンで実行

手順概要

  • OS側セットアップ
  • Athena側セットアップ
  • クエリ実行

OS側セットアップ

まずは、Linuxにtd-agentとApacheをインストールします。

$ sudo yum install httpd
$ curl -L https://toolbelt.treasuredata.com/sh/install-redhat-td-agent2.sh | sh

インストールしたままの状態だと、 td-agent ユーザがApacheのアクセスログを読めないので、ディレクトリのパーミッション変更と td-agent ユーザのグループ追加を行います。

$ sudo usermod -a -G apache td-agent
$ sudo chown apache:apache /var/log/httpd/
$ sudo chmod g+rx /var/log/httpd

td-agent.confは以下のとおりです。バケット名(s3_bucket)やPrefix(path)のパラメータはご自由に調整下さい。

<source>
  type tail
  path "/var/log/httpd/access_log"
  pos_file "/var/log/td-agent/access_log.pos"
  tag log.access
  format apache2
</source>
<match log.access>
  type s3
  s3_bucket <bucket_name>
  path "athena_apache/"
  s3_object_key_format %{path}%{time_slice}/access_%{index}.%{file_extension}
  buffer_path /var/log/td-agent/s3/access
  time_slice_format year=%Y/month=%m/day=%d/hour=%H/minute=%M
  time_slice_wait 10s
  utc
  buffer_chunk_limit 64m
  format json
  include_time_key true
  time_key log_time
</match>

ポイントは time_slice_formatパラメータに、Amazon Athenaでパーティション定義をするためのラベリングをしている点です。Athenaにおけるパーティションの詳しい説明は以下ブログを参照下さい。

あとはtd-agentとApacheを起動すれば、OS側の設定は完了です。

$ sudo systemctl enable td-agent
$ sudo systemctl start td-agent
$ sudo systemctl enable httpd
$ sudo systemctl start httpd

設定に成功していると、アクセスログがS3に以下のような形で出力されてきます。

{"host":"192.0.2.233","user":null,"method":"GET","path":"/index.html","code":200,"size":10,"referer":null,"agent":"Go-http-client/1.1","log_time":"2016-12-21T06:08:21Z"}

Athena側設定

AWS管理コンソールのAthena画面を開きます。前述のとおり、今回はオレゴンリージョンで試行しています。

Athenaでのテーブルはウィザードで作ることもできますが、今回はサンプルをベースにDDLを作成してそれを実行しました。以下のSQLをウィンドウに貼り付け、実行します。

まずはデータベースの作成です。

CREATE DATABASE IF NOT EXISTS access_table;

続いてテーブルを作成します。

CREATE EXTERNAL TABLE IF NOT EXISTS access_table.apache_access (
  `host` string,
  `user` string,
  `log_time` string,
  `method` string,
  `path` string,
  `code` int,
  `size` int,
  `referer` string,
  `agent` string 
) 
PARTITIONED BY (
    year int, 
    month int, 
    day int, 
    hour int, 
    minute int
)
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
WITH serdeproperties ( 'paths'='host, user, log_time, method, path, code, size, referer, agent' )
LOCATION 's3://<bucket_name>/athena_apache/';

パーティションの定義に、先ほど td-agent.conf の紹介の際に触れた time_slice_format の値を入力しておきます。 LOCATION の値も td-agent.conf で設定した出力先と合うように設定しましょう。

テーブル作成が完了したら、データをロードします。以下のステートメントを実行して下さい。

MSCK REPAIR TABLE access_table.apache_access;

ここまで成功したら、完了です。

動作確認

実際にクエリを流して、データが入っているか確認してみましょう。

SELECT * from access_table.apache_access LIMIT 10;

実行すると、アクセスログが入っていることが確認できます。

Athena

もう少し複雑な集計クエリも流してみましょう。

SELECT host, count(*) FROM apache_access 
where log_time < '2016-12-21T06:14:05Z' 
and log_time > '2016-12-21T06:14:00Z' 
group by host;

ある一定期間内のリクエスト数をIPアドレス毎に表示するクエリです。

Athena

こちらも問題なく結果が出せました!今回はテスト用のサーバで実験したので結果が寂しいですが、本番稼働しているサーバのアクセスログを読ませれば、もっと興味深い値が出ると思います。

つまづいた場所

Athenaを触るのが初めてで、Hiveにも触れたことがなかったのでテーブル定義を作成するのに一番苦労しました。特にPARTITIONのところはつまづきました。今回は分単位でPARTITIONを作成しましたが、この粒度についてはもう少し検討が必要だと思います。それは個人的な今後の宿題です。

まとめ

多少のつまづきはありましたが、かなり簡単にApacheのアクセスログをAthenaで出力することができました!

S3に保存はしているが使われていないログ、結構あると思います。そういったログを活用するためのツールとしてAthenaを活用してみてはいかがでしょうか?