ログの解析は日時でscpでかき集めてバッチ集計してるんだけど
- リアルタイムで集計したい
- もっと柔軟に集計したい
という人は多いんじゃないでしょうか。
リアルタイム収集はFluentdを使えばいけそうですが、集計部分を柔軟にというとどうだろう。
CookpadやAmebaはHiveを使ってるとの情報がある。
『Hive on AWS @ COOKPAD』
『Amebaのログ解析基盤』
(どっちも古い。HiveはHadoop上でSQL(っぽく)ログ解析するためのプロダクトです)
「面白そうだなー。でもHadoopよくわからん、というかサーバいっぱいいりそうだから承認通すのめんどくさい(´・ω・`)」
とか思ってたらSoftwareDesignの最新号にこんな記事が。
Cookpadの人 「Treasure Dataは...ログ解析用の商用プラットフォームを提供しています。 Fluentd経由でTreasure Dataのストレージへと保存することでメンテナンスフリーで高速な解析プラットフォームとして利用できます。 ... クックパッド規模のPVのログでも、現状では1日分のログ解析を1~2分で終えることができます」
えっ、なにそれ楽しそう!!!
というわけで使ってみた
登録やtdコマンドのインストール、認証設定
アカウント登録するだけでトライアル版が利用できます。
そしてtdというコマンドで保存先のデータベース作ったりクエリ発行したりできるっぽいです。
導入手順はここ見てください!
http://docs.treasure-data.com/articles/quickstart
インストール自体はtd-agent入れてからgemでOK
# /usr/lib64/fluent/ruby/bin/gem install td
追記)tdコマンドは最新版のtd-agentに同梱されたので、gem installは不要になりました。
そして恒例のApacheのアクセスログ突っ込んでみた
といってもここに全部書いてるんですが。
http://docs.treasure-data.com/articles/apache
いつもどおりtd-agent入れてログの集約&転送
Apacheサーバ上でtail設定
<source> type tail format apache path /var/log/httpd/access.log tag td.apache.access </source> <match *.**> type forward send_timeout 60s recover_wait 10s heartbeat_interval 1s phi_threshold 8 hard_timeout 60s <server> name aggrigation01 host 192.168.1.100 port 24224 weight 60 </server> flush_interval 10s </match>
集約サーバでtdlogプラグイン使ってTreasureDataにデータ送信
<source> type forward port 24224 bind 0.0.0.0 </source> <match td.apache.access> type copy <store> type tdlog apikey XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX auto_create_table buffer_type file buffer_path /var/log/td-agent/buffer/td </store> <store> type file path /var/log/fluent/access.log </store> </match>
指定がなければタグの後ろから2番目がデータベース名、後ろの端がテーブル名になります。アタマはtd.じゃなくてもOK.
設定によるかと思いますが、データの格納遅延は数分レベルでした。
で、とりあえず4000万件くらい突っ込んでみました
[root@test01 ~]# /usr/lib64/fluent/ruby/bin/td tables +----------+-------------+------+----------+--------+ | Database | Table | Type | Count | Schema | +----------+-------------+------+----------+--------+ | apache | access | log | 39167813 | | | testdb | testtbl | log | 1005 | | +----------+-------------+------+----------+--------+
Hiveクエリ例
ここにいろいろサンプルのってます
http://docs.treasure-data.com/articles/apache#sample-queries
time以外はJSON形式で格納されているっぽいです。v['key']で参照します。
[mikeda@test01 ~]$ /usr/lib64/fluent/ruby/bin/td query -w -d apache "SELECT * FROM access WHERE unix_timestamp()-60*60 < time ORDER BY time DESC LIMIT 10" ... +----------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------+ | v | time | +----------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------+ | {"user":"-","method":"GET","code":"200","size":"3532","host":"126.213.174.65","agent":""DoCoMo/2.0 SH03B(c500;TB;W30H18)","referer":"http://masudaK.jp/chocolate"} | 1338858502 | ...
timeでパーティション切ってるらしいので、できる限りそこで絞り込みましょう。
それでは簡単な集計の例
例1)1時間ごとの200 OKなアクセス数を24時間ぶん出してみる
[mikeda@test01 ~]$ /usr/lib64/fluent/ruby/bin/td query -w -d apache \ "SELECT from_unixtime(CAST(time/(60*60) AS INT)*60*60) AS day, COUNT(*) FROM access WHERE v['code'] = 200 AND unix_timestamp()-60*60*24 <= time AND time < unix_timestamp() GROUP BY CAST(time/(60*60) AS INT) ORDER BY day" ... +---------------------+---------+ | day | _c1 | +---------------------+---------+ | 2012-06-03 03:00:00 | 495761 | | 2012-06-03 04:00:00 | 1460441 | | 2012-06-03 05:00:00 | 1540227 | | 2012-06-03 06:00:00 | 1645884 | | 2012-06-03 07:00:00 | 1763153 | | 2012-06-03 08:00:00 | 1872281 | | 2012-06-03 09:00:00 | 1969544 | | 2012-06-03 10:00:00 | 1951634 | | 2012-06-03 11:00:00 | 1906095 | | 2012-06-03 12:00:00 | 2123442 | | 2012-06-03 13:00:00 | 2276931 | | 2012-06-03 14:00:00 | 2190546 | | 2012-06-03 15:00:00 | 1979878 | | 2012-06-03 16:00:00 | 1539153 | | 2012-06-03 17:00:00 | 1113297 | | 2012-06-03 18:00:00 | 842665 | | 2012-06-03 19:00:00 | 675836 | | 2012-06-03 20:00:00 | 674376 | | 2012-06-03 21:00:00 | 884574 | | 2012-06-03 22:00:00 | 1126021 | | 2012-06-03 23:00:00 | 1113593 | | 2012-06-04 00:00:00 | 1159783 | | 2012-06-04 01:00:00 | 1201051 | | 2012-06-04 02:00:00 | 1231317 | | 2012-06-04 03:00:00 | 930149 | +---------------------+---------+
例2)今日のリファラ数ランキング
[mikeda@test01 ~]$ /usr/lib64/fluent/ruby/bin/td query -w -d apache \ "SELECT v['referer'], COUNT(1) as numreq FROM access WHERE unix_timestamp()-60*60*24 <= time AND time < unix_timestamp() GROUP BY v['referer'] SORT BY numreq DESC LIMIT 10" ... +----------------------------------+----------+ | _c0 | numreq | +----------------------------------+----------+ | - | 16170940 | | http://mikeda.jp/wiki | 670475 | | http://d.haneta.ne.jp/mikeda | 569030 | | http://varnish.jp/ | 485617 | | http://mikeda.biz/ | 446594 | | http://oranie.jp/ | 392752 | | http://masudaK.jp/chocolate | 381886 | | http://blog.xcir.net/ | 301802 | | http://d.hatena.ne.jp/akuwano/ | 169590 | | http://blog.mikeda.jp/ | 162940 | +----------------------------------+----------+
こういう簡単なものなら1-3分で終わる感じでした。
REST APIといくつかの言語のライブラリ紹介もあります
http://docs.treasure-data.com/articles/rest-api
Rubyだとこんな感じで使えました。(ライブラリはtd-agentに入ってます)
#!/usr/lib64/fluent/ruby/bin/ruby require 'td' require 'td-client' apikey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" db = "apache" table = "access" query = "SELECT COUNT(1) FROM #{table}" cln = TreasureData::Client.new(apikey) job = cln.query(db, query) #p job until job.finished? sleep 2 job.update_status! end if job.success? job.result_each { |row| p row } end
すんごく簡単!トライアル版でもいろいろ使い道ありそう!!!
というわけでもうちょっと突っ込んでみます。