Fusicきばんブログ

Fusic基盤ユニットの非公式技術ブログ

FluentdのログフォーマットでS3に保存されたApacheのアクセスログをAmazon Athenaで集計する

突然の Amazon Web Services Advent Calendar 2016 の 15日の記事です

基盤ユニットの小山 ( @k1LoW )です。

AWS re:Invent 2016すごかったですね。

数多くのサービスが使える形でリリースされてきました。

ただ、個人的にはその後の aws-sdk-ruby が v3に上がる というエントリーを見て、awspecをどうしようか戦々恐々としています。

突然のアクセスログ集計

あるAWS上に構築しているシステムプロジェクトで、突然「月単位でのアクセス集計1年間分」という要望がどこからともなく降ってきました。

そのプロジェクトでは、アクセスログを含む様々なメトリクスをFluentd ( td-agent ) で収集して、S3のバケットに保存しています。

ただ、保存の目的がいざという時のためで、稼働している分析基盤はありませんでした。

そこで、まずはローカルのMacBook ProでDigdag+MySQLによる集計を試みました。

が、

1日立ってもログ取得が終わらず。。。

(そういえば今まではdstatのような定期的に取得するメトリクス情報のログ集計で、アクセスログのようなさらに大量のデータの取得はしていなかった。。。)

さてどうしようかとなった時に、ふと思い出したのが、そう、Amazon Athenaでした。

そうだ、Amazon Athena を使ってみよう

f:id:k1LoW:20161214200312p:plain

aws.amazon.com

Amazon Athena、ざっくり紹介するとマネージドなPrestoです(ざっくりすぎる)。

AWS提供で、S3との相性がとてもよさそうなので、もしかしていけるのでは?と思って試してみたらできました。

前提

アクセスログは s3://[bucket-name]/access_logs/[ec2-hostname]/[year]/[month]/[day]/access_log.xxxxx.xxx.xxx.gz みたいに保存されています。

S3のバケット自体はap-northeast-1 (Tokyoリージョン)にあります(Amazon Athena自体はTokyoリージョンではまだ提供されていませんが、S3バケットの指定はできますよ!)。

実際のアクセスログはFluentdの一般的な(?)ログフォーマットで、

2016-12-19T04:35:27Z ip-10-xx-xxx-xxx    {"host":"xxx.xxx.xxx.xxx","user":"-","method":"GET","path":"/path/to/?q=query","code":"200","size":"1234","referer":"-","agent":"Some User-Agent"}

というような、タイムスタンプとhostnameとJSONの複合形式です。

テーブルの作成

本来ならば「Add Table」 リンクを押してデータベースの作成からするほうがいいのですが、今回は

Query Editorで、おもむろに以下のクエリを実行して集計用テーブルを作成しました。

CREATE EXTERNAL TABLE IF NOT EXISTS default.access_logs (
  date date,
  hour int,
  min int,
  second int,
  z string,
  host string ,
  ip string,
  user string,
  method string,
  path string,
  code int,
  size int,
  referer string,
  agent string
)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.RegexSerDe'
WITH SERDEPROPERTIES (
  'serialization.format' = '1',
  'input.regex' = '^(.+)T(\\d+):(\\d+):(\\d+)(.+)\\t([^\\s]+)\\t\\{"host":"([^"]+)","user":"([^"]+)","method":"([^"]+)","path":"([^"]+)","code":"([^"]+)","size":"([^"]+)","referer":"([^"]+)","agent":"([^"]+)"\\}'
) LOCATION 's3://[bucket-name]/access_logs/'

ポイントは 'input.regex' = '^(.+)T(\\d+):(\\d+):(\\d+)(.+)\\t([^\\s]+)\\t\\{"host":"([^"]+)","user":"([^"]+)","method":"([^"]+)","path":"([^"]+)","code":"([^"]+)","size":"([^"]+)","referer":"([^"]+)","agent":"([^"]+)"\\}' でFluentdのログフォーマットに合わせた正規表現を設定しているところです。

集計SQLの実行

ここからは簡単です。

1クエリごとに小さくない金額がかかりますが、突然の依頼なので悠長なことは言っていられません。

そこは札束で殴るように

SELECT MONTH(date) AS month, count(*), SUM(size) AS total_size
FROM rkb_web_public_access_logs
WHERE host IS NOT NULL
        AND date >= CAST('2016-01-01' AS DATE)
GROUP BY  MONTH(date) 
ORDER BY total_size DESC

などと、フルスキャンでがっつり集計などしました。

まとめ

Amazon Athenaは思った以上に気軽に使えました。

ただ、クエリごとに課金されるので、ご利用は計画的に。

突然のアクセスログ集計などには良いと思います。

よい突然ライフを。


おまけ