ニフティクラウドでMongoDBは使えるか?
こんにちは、ちなつです。
本日は、@niftyで大規模分散処理やソーシャルWebシステムの企画/開発を担当しているモリフジ氏のゲスト投稿記事をご紹介します。
どうぞお楽しみに!
*********************************************************************
※この記事は2011年5月に執筆された記事になります。
<2011/06/01 17:30 追記--
※ MongoDB JPの管理人 @doryokujin さんが指摘の記事を書いてくださいました
>>「ニフティクラウドでMongoDBは使えるか?」を読んで、僕なりの考察を書いてみた
出来る限り勉強はいたしましたが、考察の足りないところ、明確にしておくべきところが不足しておりました。ユーザの方に誤解を与えてしまうことお詫びいたします。
是非、あわせてお読みください。
--2011/06/01 17:30>
こんにちは、ニフティのモリフジです。
分析などを行っているうえでMongoDBを調べています。
寄稿記事として、こちらのブログで執筆させていただきました。
今回、「ニフクラ上でMongoDBを動作させたときのパフォーマンス」についてご説明したいと思います。
■MongoDBとは
MongoDBはMySQLのようなRDB、memcachedのようなKVS、HBase/CassandraのようなDHTとは毛色の違う、「document-oriented」なデータベースです。
注:今回の記事は、必要に応じてMongoDBの紹介や、利用方法に少し触れますが、インストールの手順やその他設定についての記事ではありません。
Document-orientedって?
特徴としては公式ドキュメントでは下記4点があげられています
私見も交え、端的にいってしまうと
メリット
デメリット
という、ある種の男らしい決断を必要とする反面、男らしく調整しながら突き進むときには最適なデータベースです。
■ShardingとReplica
上記4番目の特徴としてあげた「容易なスケーラビリティ」を実現するのが「Sharding」と「Replica」機能です。これらの機能を利用する・しないによって書き込み性能・読み込み性能、次に紹介するmapReduceの性能が変わってきます。
Sharding
ドキュメントデータを複数のサーバで分割して保持する機能をShardingといいます。指定したドキュメントのキー(例えばユーザリストであれば名前など)をA-Dまではサーバ1で、E-Oまでをサーバ2、P-Zまでをサーバ3で、という具合に分割して保持します。これにより、書込性能・検索性能の向上を実現しています。
Replica
ドキュメントを保持しているサーバが破損した場合に備え、また、読み込み性能をバランスすることを目的として、保持しているデータを複数台のサーバにコピー(replication=複製)して保持しておく機能です。■MapReduce
MongoDBには、もう一つ非常に大きな武器があります。それがMapReduceという機能です。 Google BigTableやHadoopといったキーワードを耳にした方ならなじみのあるキーワードで、MapReduceを利用される方は年々増加の一途をたどっていますが、一般的にはまだまだ認知されていないかと思います。
MapReduceは巨大なデータの分析・解析という用途において非常に強力な力を発揮します。下記のような処理の一連の流れ全体で「MapReduce」と呼び、大きなデータを分割し、小さな単位で処理し、処理して縮めた結果を分析することで、巨大なデータの解析を可能にしています。
この機能は、当然、1台のマシンで行うときには、あまり意味がなく、Shardingを実現し、複数台のマシンがあるときに、より有効に機能します。分割されたブロックはそれぞれ異なるサーバでMap処理することが可能なためI/Oを節約し、Shardingで分割したサーバの台数分のCPUやMemoryで処理することが出来るからです。
少し、MongoDBで実現できる機能について少しお話しておきます。
対話shell
MongoDBをインストール後、コンソールから$MONGO_HOME/bin/mongoを実行してみてください。対話shellが起動します。
$ mongo
> show dbs
admin
config
mydb
> use mydb
switched to db mydb
> show collections
logs
system.indexes
>
こんな感じで
などを行うことが出来ます。
また、困ったときには
> help
db.help() help on db methods
db.mycoll.help() help on collection methods
(略)
> db.help()
DB methods:
db.addUser(username, password[, readOnly=false])
db.auth(username, password)
(略)
> db.logs.help()
DBCollection help
db.logs.find().help() - show DBCursor help
db.logs.count()
> rs.help()
rs.status() { replSetGetStatus : 1 } checks repl set status
rs.initiate() { replSetInitiate : null } initiates set with default settings
> db.listCommands()
addShard: no-lock adminOnly slaveOk
add a new shard to the system
applyOps: no-lock
no help defined
などと、対話shellでのhelpも充実しています。
豊富なコマンド群
上記の対話shellを起動するmongo、サーバ起動のためのmongod、shardingのクライアントとして機能するmongos以外にも多くのコマンドが存在します。mongoimport
データのバッチ投入に便利です。データベース/コレクションを指定し、json以外にもtsv, csvのデータも投入でき、また、その際のfield定義なども指定することが容易に出来ます。また、通常のファイルだけではなく標準入力も受けるため、非常に使い勝手のよいツールになっています。
$ tail -f /var/log/access.log | perl ./filter.pl | mongoimport -d mydb -c mycol -f timestamp,host,path,ua,ip
mongoexport
データベース/コレクションを指定して、バックアップ目的などでデータの出力が可能です。JSONとcsvを選択できます。また、指定した条件にマッチしたドキュメントのを指定したフィールドだけ取得することも可能です。
mongodump
データベースをバックアップ目的でdumpすることが可能です(データはbinaryで保存されます)。指定したドキュメントだけを取得することが出来ます。
mongorestore
データベースのリストア目的でdumpしたデータから復旧します。
■Benchmark
下記のような条件およびプロセスでベンチマークを行い、プロセス完了までの時間を計測しました。
データ
twitterのtweetを1.4GB (delete含めて707,259tweet)
条件
注:stripingについてはニフティクラウドにMySQLは載せられるのか?パフォーマンス大検証!をご覧ください
<2011/06/01 17:30追記>
shardのケースについて
shardkeyにはtweetの増加の少ないものとして「userのid」、時間経過に伴う増加の多いものとして「tweetのid」を設定しました。
また、indexは貼らずに検証しました(意図的に貼らなかったのですが、張ったケースを比較すべきでした。)
プロセス
おそらく日々のバッチ投入、またはログからのアクション更新のペースの頻繁なリテラシの高い企業ではリアルタイムデータ投入が行われるでしょう。このときにデータの投入がそもそももたるようでは困ります。したがってデータ投入はIOやshardingを測定する上で重要な項目です。
find
コレクションからデータを取得するコマンドです。MongoDBの場合は、ドキュメントを縦横無尽に条件付けてフィルタリングができるのでこの性能も無視できない重要な性能です。
mapreduce
MongoDBを十二分に活用するのであれば、避けられないコマンドです。簡単な解析に利用することが出来ます(簡単、と書きましたがかなり使えます)。
結果
実際に行った結果は下記の通りです(単位=ms, n=5)。
スペック | mini | large16 | ||||||
---|---|---|---|---|---|---|---|---|
sharding | 無 | 有 | 無 | 有 | ||||
striping | 無 | 有 | 無 | 有 | 無 | 有 | 無 | 有 |
mongoimport | 549.201 | 520.438 | 630.101 | 690.042 | 259.671 | 104.757 | 263.050 | 193.803 |
find | 38.378 | 42.293 | 13.618 | 14.998 | 1.044 | 1.030 | 1.124 | 1.132 |
mapreduce | 226.64 | 229.46 | 107.39 | 106.85 | 52.53 | 52.10 | 26.08 | 26.08 |
考察
全体
全体的にざっくりと見ると、当然といえば当然ですが、VMのスペックがimport/find/mapreduceに大きなパフォーマンスの差に影響を及ぼしています。
また、IO性能に関わるstripingに関しては、import、特にlarge16以外ではほとんど意味のある効果を発揮していませんでした。これはminiの場合はIOよりもmemory/cpuがボトルネックになっているためだと考えられます。
データサイズが1.4GBであるため、mini(memory=512MB)においてはfindやmapreduceにおいてIO性能の及ぼす影響が強いと予想していましたが、ほとんど見られませんでした。これは今後追求していければと思っています。
mongoimport
上記と重複しますが、スペックにおける影響が非常に強く、また、次に、large16のときにstripingの影響が出ていました。このimport処理では書き込み性能に影響が出るため、shardingの影響を予測していましたが、shardingによる性能の改善は見られないばかりか、1台で行った場合よりも劣化するという結果でした。
この結果は、mongosまたはconfigサーバがボトルネックとなりうるという要因が予測されます。今後、例えばmongosを分割し、それぞれに対して同時にimportを行い、全体としてのパフォーマンスの改善が見られるかを検討する必要があるかと思います。
find
IO性能に関わるstripingはほぼ、findにおいては影響を見せませんでした。またshardingによるfindの性能は、miniでは、およそ2倍?3倍程度の改善を示していましたが、large16ではほとんど効果が見られませんでした。同時に、stripingも影響があまり見られませんでした。
今回の程度のデータサイズであれば、cpu/memory性能が十分に高ければ分散させてIO性能を稼ぐことにあまり意義が無いと考えられます。
mapreduce
今回、一番ベンチマークを取った甲斐があるプロセスでした。stripingについては性能にほとんど影響が見られませんでしたが、shardingの効果がよく出ており、簡単とはいえ集計や計算がcpu/memory依存で行われ、mapreduceを複数台で実現することの意味が見出せたものと考えられます。
今回、すべてのデータについては、分散はほとんど見られなかったこともあり、ざっくりとした考察だけを行っていますが、いかがでしたでしょうか。実際に使う上でshardingを適切に配置し「Largeシリーズ」を使っていただければ。「Largeシリーズ」を使っていただければ、性能がスケールすることも含め、比較的性能的にもよいパフォーマンスが得られたのではないかと思っております。
なにより、VMが苦手なIOにあまり依存しない、という結果が出たということは、従来のRDBと比べ、利用シーンを選びはしますがニフティクラウドを利用するベネフィットがあるのではないでしょうか。
<2011/06/01 17:30追記>
find系のクエリについてshardキーの有無の検証
指摘されたとおりでやるべきでした。@doryokujinさんの記事をご参照ください。
sharding環境の有無でmongoimportに差が出なかったのは恐らくshardKeyの問題ではないでしょうか。前述しましたが、 shardingは事前に設定したshardKeyに従ってデータを各shardに分割しています。例えばこのshardKeyの値が "_id" を始めとした時間軸に対して増加するキーであった場合には、連続して挿入されるデータは分散されずに同じchunk、つまり同じshardに入ってしまいます。この場合にはshardingしていながら、実際にはシングルサーバーへ書き込みを行っているのと同じ、さらにはmongosサーバーを介することによってシングルよりも無駄なステップを消費しています。今回の結果の原因は、status_idをshardKeyとして使用しているような場合にはこれによるものと考えられそうです。
途中の条件のところにも記載しましたが、今回はuser_idもkeyとしてセットしているため、分散は行われていると考えています。
そのこともあり、シングルサーバーではないかと思っております(確認しようと思ったのですが、VMがなくなっていました><) 本来の、ボトルネックがどこにあったのかは、追検証できればと思っております。
このようにMongoDBのmapreduceの特性を理解せずに高スペックマシンの方が高速に動作すると思い込んで毎月数十万を無駄する可能性があります。
普段の開発では意識しているのですが、社員であること・モニター利用であることもあり、ご指摘の通り、費用対効果のことを失念していました。是非、御利用は計画的によろしくお願いいたします。