最近ようやく仕事でガッツリFluentdとMongoDBを触るようになってちょっとハマったことが あったので誰かの役に立つかも知れないので書いておく。
Fluentd界隈は開発が活発なので、数ヶ月後にはこの記事の情報も恐らく古くなっているのでご注意ください。
結論
書いてたら長くなってしまったので先に要点というか結論を書いておく。
apache=>fluentd=>MongoDBとapacheのアクセスログをMongoDBに入れたときにcodeやsizeといった数値が文字列(string)として入っていたtd-agent.confのformatを自作すると、時間以外のフィールドが文字列(string)として扱われる- fluent-plugin-typecastを利用することで
codeやsizeといった特定のフィールドを、stringやintegerなどの任意のデータ型に変換可能。今回の場合はsizeとcodeをintegerとして扱うように変換して解決した - MongoDBのAggregation Frameworkは大変便利
前段
MongoDBは2.2からAggregation Frameworkというのが 使えるようになっていて、これまでMapReduceなどを用いないと実行出来なかったデータの集計作業などが コマンド一発で出来るようになっているとのこと。 Fluentdを利用してMongoDBに貯めていたapacheのログからvhost毎のトラフィック集計作業を行おうとしてた。
MongoDBに入っているapacheのログデータは下記のような形
1 2 3 4 5 6 7 8 9 10 11 | |
hogemoge.glidenote.comの転送量の集計をするために下記コマンドでsizeで集計をかける。
1 2 3 4 5 | |
…、集計出来ないッ!
aggregation frameworkで集計出来ない原因
なぜ集計出来ないのか調査すると、sizeが文字列として扱われていた。ちなみに各フィールドのデータ型は下記のような形で調べられる。(ダブルクオートで囲まれているので、その時点でintegerではないんですが調査中は全く気づかなかった…)
1 2 3 4 5 | |
数値が文字列として扱われている問題の原因
同じような現象を調べて下記有益情報を発見。
問題が発生した時の構成
問題が発生していたときの構成。(WEBサーバ約200台で、LOGサーバは1台の構成)

結論を言うと今回の現象はLOGサーバ側で利用していたfluent-plugin-parserのfixed_parser.rb部分で発生していた。fluentdのparser.rbを利用しても同様に発生する問題(2013年4月8日現在)
なぜ数値が文字列(string)として扱われるのか
解決方法を探るためにソースを見てみると、format apache2の場合はApacheParserが利用されてsizeやcodeにto_iの処理が入っており数値に変換されているが、formatを自分で書くとRegexpParserが利用されてtime以外は文字列として扱われている。今回はformat apache2がそのまま利用出来ないログの形式でformatを自分で書いていたのも一因としてある。
問題の解決方法
問題の原因がわかり、解決方法をいろいろ試していたら、弊社の@banyan先生からfluent-plugin-typecastというのがあると有益情報をゲット。
早速下記のような形で導入
1
| |
td-agent.confのfluent-plugin-typecastの部分は下記のような形
1 2 3 4 5 | |
apacheのログを流してみると、ちゃんとsizeとcodeが数値(integer)としてMongoDBに入るようになった。
Aggregation Frameworkで再度集計してみる
当初の目的であるMongoDBのAggregation Frameworkを再度試してみる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
一瞬で集計が完了。素晴らしい!!($matchを書けるvhost、timeとかにindex貼ってないと多分死にます)
改善後の構成

この構成で1秒に約4000ドキュメント、1日で約3億5千ドキュメントをMongoDBに突っ込んで 数日様子を見てますが、特に大きな問題も無く稼働中です。
当初どこが問題の原因か全く検討も付かなくて調査に半日近く時間を要した。 仕事でガッツリ触らないと覚えないし、勘も働かないなーと改めて感じた。