開発メモ#6 : ログの取り扱い : GrowthForecast, Amazon S3, Treasure Data で心労ゼロ
開発メモ#6 です。前回から少し間があいてしまいました。
開発メモ#2 : AWS でのホスト / クラウドネイティブなデプロイ - naoyaのはてなダイアリー で書いたように、EC2 へのアプリケーションのデプロイにあたっては Elastic IP の利点を活かしてカジュアルにホストを入れ替えまくっています。ちょっとこのデプロイは慎重になりたいな、と思ったらスナップショットからインスタンスを立ち上げては切り替える、の繰り返し。
この運用をしていると、スナップショットとの差分ができやすいのは chef-solo で吸収するというのが前回、前々回のはなし。
もう一点問題があります。アクセスログやアプリケーションのログです。フロントエンドのサーバをあっちこっち切り替えているうちに、そのままではログが分断されてしまう。ホストを Terminate しようものならログは消失してしまいます。
この手のケース、ログサーバーなんかを立てて古くは syslog agent、最近は fluentd に飛ばして別途集約しておくというのが定石かと思います。
しかしまあ、個人でやってるアプリケーションだったりするとわざわざログサーバー立てるまでもないよね。なんか良い方法ないかな、ということもあるはず。そうでなくても、少ない人手でログサーバーを運用するのはちょっと面倒という話も。
ログのユースケース
そこで、そもそもログファイルの主なユースケースを考えます
- 障害発生時などの調査用
- アクセス数その他の統計データ解析用
- ログの提出を求められるようなイレギュラーなイベントへの対応用
あたりでしょうか。これに対し
- 障害発生時には、台数がそれほどでなければローカルのものを漁れば OK
- 統計用は、ビッグデータのクラウドサービスである Treasure Data に送っちゃえば OK
- なお、通常のアクセス解析は Google Analytics
- レスポンス時間やロードアベレージ的なリアルタイム解析は GrowthForecast へ飛ばす
- 長期保存用は Amazon S3 に保存して、更に古いのは Amazon Glacier で凍結してしまえば OK
という方針を採ることで、自分はログサーバなしで要件に対応するようにしました。
Treasure Data については後日もうすこし詳細に書いてみようかなと思ってますが、簡単にいうとログデータを継続的に送り続けておいて、解析したいと思ったら SQL のような言語 (HiveQL) で(大規模並列に)解析がかけられる、というサービス。
Amazon Glacier は、AWS のアーカイブサービスで、普段は参照しないけど必要なときには時間がかかってもいいから取り出したい、というデータを安価に保存することができるサービスです。
ログは fluentd で飛ばす
例によってログは fluentd で飛ばします。基本ログファイルは LTSV で吐いておいて、それを fluentd でつかんで転送。
入力は
<source> type tail_labeled_tsv path /var/log/nginx/access.log tag nginx.access pos_file /var/log/td-agent/nginx.access.log.pos </source>
としている。LTSV 解析の tail_labeled_tsv 相当の機能は既に本体に取り込まれてるので今ならプラグインを使う必要はない。
出力は以下のように GF、S3、TD へそれぞれ転送。途中、extract_query_params プラグインを使っています。これはアクセスログ内の "/entry?foo=bar&bar=baz" みたいなフィールドを { "foo" : "bar", "bar" : "baz" }
みたいなデータ構造に変換してくれるもの。TD に送るにあたっては、クエリパラメータの値を軸にした集計なんてのもよくやるのでそれらに分解して送信しておくと良い。
なお、以下の例は設定の一部です。
<match nginx.access> type copy ## GrowthForecast へレスポンスタイムを送る <store> type growthforecast gfapi_url http://localhost:5125/api/ service nginx section response_time name_keys response_time,upstream_response_time </store> ## Amazon S3 へ保存 <store> type config_pit <pit aws> type s3 s3_bucket amazlet-ec2-log s3_endpoint s3-ap-northeast-1.amazonaws.com aws_key_id $pit[aws_access_key] aws_sec_key $pit[aws_secret_access_key] path nginx/ buffer_path /var/log/td-agent/buffer/s3 time_slice_format %Y/%m/%d/access_log-%Y%m%d-%H </pit> </store> ## extract_query_params クエリパラメータを分解・展開しておく <store> type extract_query_params key path add_tag_prefix extracted. only locale, __mode, affiliate_id, keyword, asin </store> </match> <match extracted.nginx.access> type copy ## クエリパラメータも込みで、Treasure Data へ飛ばす <store> type config_pit <pit treasuredata> type tdlog apikey $pit[td_apikey] auto_create_table buffer_type file buffer_path /var/log/td-agent/buffer/td use_ssl true </pit> </store> … </match>
こうやって飛ばしておくとGF で以下のように風にグラフ化されて
S3 にちゃんとログが小分けにされて保存されて
Treasure Data で SQL みたいなもので簡単に解析ができる。
$ td query -w -d nginx "select v['asin'] as asin, count(1) as cnt from access group by v['asin'] order by cnt desc limit 100" Job 1792464 is queued. Use 'td job:show 1792464' to show the status. queued... started at 2013-02-18T01:26:58Z Hive history file=/tmp/1624/hive_job_log__800096608.txt Total MapReduce jobs = 2 Launching Job 1 out of 2 Number of reduce tasks not specified. Defaulting to jobconf value of: 12 In order to change the average load for a reducer (in bytes): …
これだけやってもログの管理はしなくていい。さっぱりしますね!
S3 ⇒ Glacier への変換は自動で
Amazon S3 へ保存したログは、ある程度の日数が経ってもういいかなと思った頃には Glacier でアーカイブ化してしまいたい。そうすることで、古いログは参照しづらくはなるけどその分ストレージ価格がずっと安価になる。Amazon S3 の 1/10 の価格で、1GB 1円 です。
「その変換のために定期的にバッチスクリプトとか回すの?」─ いいえ、S3 でチェックボックス一個です。
という風にバケット全体に「30日経ったら Glacier に移す」という風に設定できる。簡単!
豆知識: Glacier には S3 を経由せずに保存することもできるけど、その場合は Glacier に保存されたアーカイブが元々どういうファイルだったかという紐づけは自分で管理しなければいけないらしい。S3 経由にしておくと、そもそも S3 のインタフェースで Glacier のファイルを引っ張り出せるので、その必要がない。ただし S3 経由で保存したものは S3 経由でしか取り出せなくなり、Glacier API 直接では取り出せない。その逆もまた然り・・・ということを昨日の #awspad で知った。
なお、Glacier オプションを有効にしておいたのにそれまで取り出し方を知らなかったのは秘密だ。
雑感
最終的にフロントエンド周りのサーバーが複数台構成になってくると、結局ログを GF なり TD なりに転送するまえにいったん集約する必要が出てきてログサーバーが必要になるだろうけど、それまではこのやり方で運用できるでしょう。複数台になった場合も、ログを保存するストレージ周りを気にしなくて良いという意味でも中長期的に負担の少ない運用だと思います。
仮にもうちょっと小規模な集計とか調査をばりばりやりたいというニーズが出てきたら、それ目的の mongodb なり何なりを用意して保存先を追加すれば OK。長期保存や大規模解析は S3 や TD に任せたままにしておけるのでその mongodb の役割も必要最小限にできるし気を病まなくて良い。
とにかくログ周りをどうするか、ストレージをどうするか、ということをもう悩まなくてもいいのはとても気がらくでいいですね。
fluentd をはじめ、こんな便利な各種ツールやサービスを開発・運営していただいている皆様には足を向けては寝られませんね。ただし、実際どの方角にいるか知らないから、案外毎晩足を向けてる可能性は否めません。