2012-02-07
fluentdを試してみた
Fluentd meetup in Japan on Zusaar
僕は行ってないんですがTwitter、Ustream、スライド、ブログなどを見る限りだいぶ盛り上がったようですねー。僕自身が仕事で使う予定は今のところ無いんですがログ解析関連の仕事をしていることもあるので素振りしてみようと思います。
環境はVirtualBox上のCenOS 5.7(x86_64)を使いました。
fluentdはRuby 1.9上で動くんですがCentOS 5.7に入っているのはRuby 1.8.5です。Ruby 1.9のインストールから始めるとはまりそうなのでyumでインストールできるtd-agentを使います。td-agentはfluentdの安定版パッケージという位置付けのようです。
試したのは下記3つです。
最初のfluent-catでログを送るで参考にしたサイトはこちらです。
[root@localhost ~]# vim /etc/yum.repos.d/td.repo [root@localhost ~]# cat /etc/yum.repos.d/td.repo [treasuredata] name=TreasureData baseurl=http://packages.treasure-data.com/redhat/$basearch gpgcheck=0 [root@localhost ~]# yum install td-agent
設定ファイル/etc/td-agent/td-agent.confは下記のようにします。
<source> type tcp </source> <match debug.**> type file path /var/log/fluent/debug </match>
あとは事前準備です。
[root@localhost ~]# mkdir /var/log/fluent [root@localhost ~]# chown td-agent:td-agent /var/log/fluent
そして起動します。
[root@localhost ~]# service td-agent start
td-agentのログが /var/log/td-agent/td-agent.logに出ます。下記のような感じ。エラーがでないことを確認します。ありがちなのはAddress already in use とかPermission deniedかな。
2012-02-07 22:31:24 +0900: reading config file path="/etc/td-agent/td-agent.conf" 2012-02-07 22:31:24 +0900: adding source type="tcp" 2012-02-07 22:31:24 +0900: adding match pattern="debug.**" type="file" 2012-02-07 22:31:24 +0900: running fluent-0.10.6 2012-02-07 22:31:25 +0900: listening fluent socket on 0.0.0.0:24224
fluent-catを使ってtd-agentにログを送ります。
[root@localhost ~]# echo '{"hoge":"fuga"}' | /usr/lib64/fluent/ruby/bin/fluent-cat debug.test
結果を確認するとちゃんと時間、タグ、JSONが出てますね。
[root@localhost ~]# cat /var/log/fluent/debug.20120207.b4b85fcecacf316bc
2012-02-07T22:32:17+09:00 debug.test {"hoge":"fuga"}
参考にしたのはこのサイトです。
イベントログ収集ツール fluent を試しに使ってみる - 文字 - はてな自習室
td-agent.confを下記のように設定します。
<source> type tail format apache path /var/log/httpd/access_log tag apache.access </source> <match apache.access> type file path /var/log/fluent/access_log </match>
このまま起動すると/var/log/httpdのパーミッションが700でroot:rootという所有権なのでtd-agentだと読み込めずに下記のようにPermission deniedになります。
2012-02-07 22:47:49 +0900: unexpected error error="Permission denied - /var/log/httpd/ access_log" 2012-02-07 22:47:49 +0900: /usr/lib64/fluent/ruby/lib/ruby/gems/1.9.1/gems/fluentd-0 .10.6/lib/fluent/plugin/in_tail.rb:97:in `stat'
なので
[root@localhost ~]# chmod g+rx /var/log/httpd
とするとうまくいきます。o+rxでうまくいかないのはよくわからんです。。。td-agentユーザってrootグループじゃないのに。rootLinux弱者だ。。。
ともあれ、service httpd startして下記のようにHTTPアクセスします。
[root@localhost ~]# curl http://localhost
|<<
そうすると下記のように構造化されたログが出力されます。
>||
[root@localhost ~]# cat /var/log/fluent/access_log.20120207.b4b860095492522d2
2012-02-07T22:48:39+09:00 apache.access {"host":"127.0.0.1","user":"-","method":"GET","path":"/","code":"403","size":"5043","referer":"-","agent":"curl/7.15.5 (x86_64-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5"}
最後にMongoDBにApacheアクセスログを出力してみましょう。
参考にしたのはこちら
Treasure Data Blog | Real-Time Log Collection with Fluentd and MongoDB
[root@localhost ~]# vim /etc/yum.repos.d/10gen.repo [root@localhost ~]# cat /etc/yum.repos.d/10gen.repo [10gen] name=10gen Repository baseurl=http://downloads-distro.mongodb.org/repo/redhat/os/x86_64 gpgcheck=0 [root@localhost ~]# yum install mongo-10gen-server [root@localhost ~]# service mongod start
この時点ではデータは入っていません。
[wyukawa@localhost ~]$ mongo MongoDB shell version: 2.0.2 connecting to: test > show dbs; local (empty)
次にfluent-plugin-mongoをインストールします。
[root@localhost ~]# /usr/lib64/fluent/ruby/bin/fluent-gem install fluent-plugin-mongo
td-agent.confを下記のようにします。
<source> type tail format apache path /var/log/httpd/access_log tag mongo.apache </source> <match mongo.**> # plugin type type mongo # mongodb db + collection database apache collection access # mongodb host + port host localhost port 27017 # interval flush_interval 10s </match>
この状態でtd-agentを起動すると下記のメッセージができます。
Starting td-agent: Able to load bson_ext version 1.4.0, but >= 1.5.2 is required. **Notice: C extension not loaded. This is required for optimum MongoDB Ruby driver performance. You can install the extension as follows: gem install bson_ext If you continue to receive this message after installing, make sure that the bson_ext gem is in your load path and that the bson_ext and mongo gems are of the same version.
bson_extをインストールしろといっているのでそうします。
[root@localhost ~]# /usr/lib64/fluent/ruby/bin/gem install bson_ext
[root@localhost ~]# curl http://localhost/
その後MongoDBの中を見ているとデータが入ってます。
> show dbs;
apache 0.015625GB
local (empty)
> use apache;
switched to db apache
> show collections;
access
system.indexes
> db.access.find();
{ "_id" : ObjectId("4f313256e138231825000001"), "host" : "127.0.0.1", "user" : "-", "method" : "GET", "path" : "/", "code" : "403", "size" : "5043", "referer" : "-", "agent" : "curl/7.15.5 (x86_64-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5", "time" : ISODate("2012-02-07T14:16:42Z") }
以下のように100アクセスするとdb.access.count();の値が100づつ増えます。
[root@localhost ~]# ab -n 100 -c 10 http://localhost/
td-agent使えばかなり手軽にログ解析できそうですね。wktkしてきました。
fluentdについて調査する場合は下記からいろいろとたどれそうですね。
fluentdのブログ記事などまとめメモ - oranieの底辺日記
いじょ。
2012-02-06
OLAP関数
テレコム業界のCDR(Call Detail Record)の解析をOracleからHiveにマイグレーションした資料を見つけたのでめもっておく。
この資料を見つけたきっかけはp22にあるOracleのrank() over (partition by ... order by ...)みたいなOLAP関数をHiveでどのように書き変えるかの部分を見たからだ。
そもそもオレはDB弱者でOLAP関数なぞ使った事も無いし知らなかったのだがWeb+DBのミックさんの連載を読んで便利というか直感的だなあと思ったものだ。
MySQLにはOLAP関数が無いらしいので同じ事を実現しようとすると相関サブクエリになったりして可読性はあんま良くないと思う。
具体例はこの辺。
- SQLアタマアカデミー:最終回 OLAP関数で強力な統計処理を実現!―手続き型から理解するSQL (3)OLAP専用関数|gihyo.jp … 技術評論社
- MySQLで分析関数を模倣1(前編)(1/4):CodeZine
Hiveで処理する場合はOracleと違ってまだOLAP関数がないのでうごうごとやらないといけない。
ただHiveも0.7になってRank関数は実装されたようだ。
[#HIVE-1304] add row_sequence UDF - ASF JIRA
しかしここで指摘されているようにアンドキュメントなようだw
この辺の集計処理をHiveでやるのかそれとも例えばSqoopでPostgreSQLにデータを取り込んでRDBMSに任せるのかとかいろいろとやり方はありそうだ。
2012-01-28
シェルスクリプトのパスとパイプ
考えてみるとここ1年はJavaのコードはほとんど書いていなくてそれよりはシェルスクリプトを書いている機会の方が多かった。
なのでここら辺でシェルスクリプトを書いていてハマったところというかちょっとしたTipsをメモっておこうと思う。前提としてBashである。
まずはパスについての話。
シェルスクリプトでパスをべた書きしているとポータビリティが失われてしまい別のマシンに移行する場合に困るケースが多い。
なのでこれをスマートに解決したいわけである。
かといって単純に相対パスを使っていると困るケースがある。
例えばある基準となるディレクトリ${BASE_DIR}があってその下にシェルスクリプトをおくディレクトリscriptsとログをおくディレクトリlogという構成にしたいとしよう。
scripts/ log/
この場合にシェルスクリプトの中で
echo ... > ../log/log.txt
とかやるとシェルスクリプトを実行する場所がscriptsに固定されてしまう。
それで良いケースもあるだろうが、もうちょっとスマートにやる場合は基準となるディレクトリ${BASE_DIR}の絶対パスを求めてそれを使うことである。
どう求めるかというとこんな感じ。
BASE_DIR=$(cd $(dirname $0);pwd)
説明はまるっと借用させていただくw
$0は実行中のシェルスクリプトのファイル名。
dirnameを使うことで、シェルスクリプトのディレクトリーが取得できる。
ただしこれは相対パスかもしれないので、cdでそのディレクトリーに移動し、pwdでその場所(絶対パス)を取得している。
UNIXシェルスクリプトメモ(Hishidama’s UNIX shell script Memo)
このように設定した${BASE_DIR}を使ってパスを作ればよい。
echo ... > ${BASE_DIR}/log/log.txt
この手の共通的な設定は別ファイル、例えばconfig.shにくくりだして読み込むのがよろしい。
こんな感じにね。
cwd=`dirname $0` . ${cwd}/config.sh
つづいてはパイプ周りの話。
例えばあるディレクトリ${WORK_DIR}にあるデータファイル全てを1つ1つ処理したい。
ただし仕様としてある1つのファイルでエラーが起きた場合も処理を続行したい。
しかし1ファイルでも異常があったら最終的には異常終了にしたい。
全てのファイルを正常に処理できたときのみ正常終了とする。
言葉だと伝わりづらいと思うが、シェルスクリプトで書くとこんな感じになるだろう。
#!/bin/sh cwd=`dirname $0` . ${cwd}/config.sh exit_code=0 ls ${WORK_DIR} | while read datafile do ${cwd}/process.sh ${WORK_DIR}/${datafile} if [ $? -ne 0 ]; then exit_code=1 fi done exit ${exit_code}
しかしこの方法では仕様を満たさない。
ループの外側のexit_codeが1になることは無いから。
つまり1つのファイルでエラーが起きた場合でも全体としては正常終了する。
何故かというと | (パイプ)処理から先は別プロセスで起動していて、ループの外側と内側のexit_code変数は別物だから。
解決策はリダイレクトを使う。
#!/bin/sh cwd=`dirname $0` . ${cwd}/config.sh exit_code=0 ls ${WORK_DIR} > datafile.list while read datafile do ${cwd}/process.sh ${WORK_DIR}/${datafile} if [ $? -ne 0 ]; then exit_code=1 fi done < datafile.list exit ${exit_code}
これならOK。
リダイレクトするとそのファイルの処理を考えないといけないのが南天のど飴なのであるがこれは仕方ない。
似たような話だが、下記のようにすると多重ループをexitで抜けられない。
#!/bin/sh cwd=`dirname $0` . ${cwd}/config.sh ls ${WORK_DIR} | while read dir do ls ${WORK_DIR}/${dir} | while read datafile do ${cwd}/process.sh ${WORK_DIR}/${dir}/${datafile} if [ $? -ne 0 ]; then exit 1 fi done done
これはさっきと違って1ファイルでも異常があったら処理を続行せずに終了したいパターン。
これもリダイレクトすればOK。
#!/bin/sh cwd=`dirname $0` . ${cwd}/config.sh ls ${WORK_DIR} > dirs.txt while read dir do ls ${WORK_DIR}/${dir} > dir.txt while read datafile do ${cwd}/process.sh ${WORK_DIR}/${dir}/${datafile} if [ $? -ne 0 ]; then exit 1 fi done < dir.txt done < dirs.txt
もしくはこんな感じでdoneの直後でexitする。
#!/bin/sh cwd=`dirname $0` . ${cwd}/config.sh ls ${WORK_DIR} | while read dir do ls ${WORK_DIR}/${dir} | while read datafile do ${cwd}/process.sh ${WORK_DIR}/${dir}/${datafile} if [ $? -ne 0 ]; then exit 1 fi done if [ $? -ne 0 ]; then exit 1 fi done
いじょ。
2012-01-22
ログ解析についてつらつらと考えていること
ログ解析についてつらつらと考えていることを書いてみたいと思います。
Hadoopを用いたログ解析によってマーケティングを変革し売り上げを向上させようという話はよくあります。
この手の話はたいていBtoCで例としてはメールでレコメンドして商品を買ってもらうとかですね。
ログ解析がどういうフローかというと、ログを埋め込んでログを収集して蓄積して解析してそのレポートを見て何らかの施策を打つ、という感じになります。
図にするとこんな感じ
今話題沸騰中の「Fluentd」はログ収集を担当します。といいつつ僕自身はFluentd使ったことないです。記事を読んだくらいです。
ちなみにどれぐらい話題沸騰中かというとこれぐらい定員オーバーしてます。すごすぎ。
Fluentd meetup in Japan on Zusaar
ログ埋め込みはJavaならLog4j使って埋め込んだりするでしょう。
Apacheのアクセスログ使うのならログ埋め込みは必要無いですが業務的なログは取れません。URLに業務的な情報を付加すれば別ですが。
Fluentdやアクセス解析ソフトを使っている場合は生ログをパースする必要はないかもしれないですが、使っていないならパースして必要な情報を取得する必要があります。
JavaScriptや画像へのアクセスログを除く必要もありますね。僕はやったことないですがなんだか凄く大変そうですね。。。
ログ埋め込む人とパースする人(解析する人)が同じならいいですが、そうでないことが多いでしょう。
同じでない場合ログ埋め込んだ人が何をもって正しくログを埋め込んだかを確認するんでしょう。。。
仕様書なのかなあという気がしますが、そんなちゃんとした仕様書を書く工数があるのかという話と、もっと根本的にはログというプログラム本来の動きに直接関係しないことにどれだけ工数をかけられるかというのがあります。
てか、例外でさえ無視されやすいのに例外でもないログを考慮できるかというと難しい気がします。
でもこれは能力の話ではなくマネジメントの話ですね。ログ解析で何をしたいのか?ってところがスタートでそこからかけられる工数の中から最低限のことをやっていくという話でしょうね。
サービスレベルの話もあります。収集プロセスは毎日だったりストリーミング的にまわっているかもしれないですがこれが1日ダウンしてもOKなのかとか。さすがに24時間365日動いている必要もない気がしますが。
どのような手法でやるにせよまあHadoopに蓄積します。そして解析します。HiveやPigを使うのが一般的かもしれないですが、直MapReduceやHadoop Streamingでやる手もあるでしょう。
この辺で問題になってくるのが解析結果の信頼性です。解析結果が正しいことをどう担保するのか。これは悩ましいです。プログラムがスタックトレース吐いて落ちるならすぐわかりますが、数値が違うというバグはそう簡単には見つかりません。検算するにしても何を正しいと仮定するのでしょうか。場合によっては2人で同じ仕様の解析プログラム書かせて結果を比べるという手もあるかも。
最後はビジュアライズしてレポーティングですね。商用のBIツール使うのかExcelのピボットテーブル使うのかはおいといて解析結果を見やすい形にして施策を打つ人に見せる必要があります。
こう見ていくとログ解析というのは大変です。データ量が増えるとなおさらです。こうなると費用対効果がどうなんだという話になりそうです。
費用対効果はA/Bテストで調べるんだと思いますが、それやるのも一手間かかるでしょう。
そういうこともあるのでログ解析のゴールとして売り上げ向上というよりは不正データの検出のほうが向いているのかなあという気がします。
なんでそう思ったかというと最近でたこの記事を読んだからですがw
――そうなると企業としてはビッグデータ活用の投資対効果をどう測るかが重要になると思うのですが。
佐藤氏:そのとおりです。その意味でも、ビッグデータ活用の目的をいきなり収益の向上やマーケティングの変革に置くよりも、カード会社が行っているカード不正利用の洗い出しのように、リスク管理やリスク対策に置くほうが現実的ではないでしょうか。つまり、そうしたほうが会社の投資は引き出しやすいということです。
また、「ビッグデータの分析によって違法行為はすぐに見つけられる」と宣言できるようにしておくことは、それだけで犯罪の抑止につながります。ビッグデータの分析で違法行為を発見するのは簡単なことではないかもしれませんが、たとえ実効性が低くても、犯罪の抑止になればそれで十分という割り切った考え方もできるはずです。
ビッグデータの間違いを正す(前編)|ストレージ|トピックス|Computerworld
他にはソーシャルゲームでクリアが難しく脱落者が多い箇所をチューニングして退会を防ぐとかはログ解析の価値がありそうです。要はマイナスを減らすディフェンスの話ですね。売り上げを向上させるとかそういうオフェンスの話ではなく。
というようなことを今晩のプレミアリーグのビッグマッチ前につらつらと考えていました。いじょ。
2012-01-14
プレミアリーグに関する情報源
今シーズンからプレミアリーグをTV(JSPORTS)で見るようになったんですが関連して面白そうな情報源があったのでメモっておく。英語の勉強にもいいかも。
プレミアリーグを紹介する書籍としては下記があります。2009年出版なので選手の所属が変わってたりしてますが(例えば表紙にはアーセナルのセスクが写っている)参考になります。
- 作者: 西岡明彦
- 出版社/メーカー: 講談社
- 発売日: 2009/11/07
- メディア: 単行本
- クリック: 11回
- この商品を含むブログ (3件) を見る
フットボールと英語という切り口で書かれた本としては下記があります。CD付き。ベンゲルの英語がフランス語訛りなのがよくわかりますw
- 作者: フットメディア
- 出版社/メーカー: ジャパンタイムズ
- 発売日: 2010/05/20
- メディア: 単行本(ソフトカバー)
- クリック: 33回
- この商品を含むブログ (3件) を見る
Footballイングリッシュでは英語の情報源をいくつか紹介しています。それが下記なのですが、この辺のサイトを見るのも面白いかも。
テレビ局のスポーツサイト
- THE Sun
- Daily Mail
- Daily Mirror
- THE TIMES
- The Daily Telegraph
- The Guardian
- THE INDEPENDENT
公式ウェブサイト
- The Premier League
日本語での情報源としては下記があげられると思います。
イングランドサッカー,プレアミリーグ,クラブ,代表チーム,チーム,移籍情報,動画,ビデオ - Goal.com
電子雑誌としては
theWORLDがあります。iPadで購入してみましたが操作性はイマイチな気がします。コンテンツは良いと思いますが。
コラムは下記がなかなか面白いです。
ブログだと下記ですね。
またJSPORTSではサッカーネット プレスパス:プレミアリーグ日誌:So-netブログに書かれているようにサッカーに関する関連番組をやっています。
月曜日〜金曜日まで「デイリーサッカーニュース Foot! 」というサッカー番組があります。毎回見ているわけではないですが、月〜水が欧州サッカーのネタで、木曜日がJリーグ、金曜日が南米サッカーという感じのようです。
月曜日〜木曜日が西岡さんMCによる22:00-22:30枠で金曜日が倉敷さんMCによる22:00-22:50枠のようです。
また「デイリーサッカーニュース Foot! 」の後に「サッカーネット プレスパス」という20分番組(月曜日〜木曜日)があって、これも毎回見ているわけではないですが、コメンテーターがすげえ言いたい放題で面白いですw 外国の番組を吹き替えているんですが日本だとあそこまで言いたい放題な番組は無いでしょうね。関係者が見たら怒りそうですが部外者が見ている分には面白いです。ただ再放送は無いようですね。
ここまで書いて思い出しましたが、解説は粕谷さんが面白いです。これは好みが分かれるかもしれませんが、批判する場合も理由をちゃんと言うしその理由に結構納得できるので個人的には好きですね。むしろ実況の人が偉そうにプレーをdisってる方が違うかなーと思いました。

