ログの解析は日時で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
すんごく簡単!トライアル版でもいろいろ使い道ありそう!!!
というわけでもうちょっと突っ込んでみます。