Gunosyではログ解析周りや推薦エンジンでMongoDBを使っています。
ちょっと前に勉強会でMongoDBのMapReduceでログ解析やってるよって話をしたところ、
- MongoDBのMapReduceって遅くない?
- データ量増えるとリソース相当使わない?
とのツッコミを頂きました。
指摘自体は正しいと思っていて、データ増えるとすぐ計算時間やサーバのリソース使用量が大変なことになります。
それを避けつつ、節約して運用するためにGunosyのログ解析周りではCapped Collectionを使ってます。
Capped Collectionって?
ご存知の方も多いと思いますが、念のため本家から引用すると、
Capped collections are fixed-size collections that support high-throughput operations that insert, retrieve, and delete documents based on insertion order.
要はサイズ固定で高速に使えるcollectionだと思っていただければ結構です。
長所
- サイズ固定なので不用意にリソースを使用し過ぎることがない
- 割と高速
短所
- 後からcapサイズが変更しづらい。(できなくもないです)
Capped Collectionを利用する場合は以下のコマンドで確認できます。
// 新しくコレクションを作る場合
db.createCollection( "mycol", { capped: true, size: 100000 } )
// すでにコレクションが存在する場合
db.runCommand({"convertToCapped": "mycoll", size: 100000});
コレクションのstatsを見れば、cappedになっているか確認できます。
> db.mycol.stats()
{
"ns" : "test.mycol",
"count" : 0,
"size" : 0,
"storageSize" : 12288,
"numExtents" : 1,
"nindexes" : 1,
"lastExtentSize" : 12288,
"paddingFactor" : 1,
"systemFlags" : 1,
"userFlags" : 0,
"totalIndexSize" : 8176,
"indexSizes" : {
"_id_" : 8176
},
"capped" : true,
"max" : NumberLong("9223372036854775807"),
"ok" : 1
}
どう使っているか
以下の2点に注意してログ解析部分に使っています。
- 解析項目に合わせてログフォーマットを毎度用意している
- 計測に必要なログの保存日数に合わせてCapサイズを決定している。
解析では生のアクセスログを殆ど使っていません。
ログ解析もサーバのコードも同じ人間が担当するので、解析項目に合わせて新しく必要最低限のデータのみ送信するロガーを適宜実装して、同時にログ集計用スクリプトも用意する形になっています。(このへんはFluentd使っている)
アクセスログだとどうしてもpathだとかリクエストのパラメタだとかが入ってしまうので、collectionサイズが肥大化してしまいますが、解析項目に対して本当に必要なデータのみMongoDBへ保存するとそれほど容量は使いません。
ちなみに生のアクセスログも一応MongoDBへCapかけて保存していますが、ほとんどはS3へ保存→Redshiftへ、という流れになってます。
この運用だと、解析自体もそれほど大きなリソースを使わず今のところ維持できています。
この運用の欠点
長期間のデータを後から解析したくなったときは、Collection内にそれほど長期のデータが保存できていないので、ここは社内だとRedShiftを利用しています。
まとめ
Capped Collectionをうまく使うとそれなりの規模でもリソースを節約しながら性能を維持してMongoDBを運用できますよという話。