MongoDBを半年運用してみた(のフォロー)
某社との合同勉強会のLTで発表したMongoDBを半年運用してみたが、えらいはてブされててびっくり。。。あのままだとMongoDBは絶対使わないって結論になっちゃいそうなので、自分をフォローする形でエントリを書きたいと思います。
資料はこちら。
コネクションエラー多発
これは、7月にmongosの場所がmongodからSocketサーバ/Webサーバ/管理サーバに移動した件と関係しています。
まず、Socketサーバ/Webサーバ/管理サーバともにJavaで実装されているので、MongoDBへの接続はJavaの公式ドライバーを利用しています。当初のドライバーの利用方法は、
// Shard1, Shard2, Shard3のPRIMARYと同居してるmongosのホストアドレス for (String hostAddress : hostAddresses) { String[] split = hostAddress.split(":"); String host = split[0]; int port = Integer.parseInt(split[1]); ServerAddress address = new ServerAddress(host, port); addresses.add(address); } Mongo mongo = new Mongo(addresses, options);
といった感じでした。が、よくよくJavadocを見てみると、コンストラクタに以下の記述が。
Creates a Mongo based on a replica set, or pair.
ここで渡せるホストアドレスは、ReplicaSetまたはReplicaPair(2台1セットの構成。現在非推奨)の全ホストのようです。設定した中からPRIMARYを探し出して接続し、PRIMARYが死んだ場合は次に昇格したPRIMARYに接続し直す、と。つまり、Sharding構成の場合にそれぞれのmongosのホストアドレスを指定してたのは誤っていたようです。
7月以前は、Socketサーバ/Webサーバ/管理サーバの合計7台でShard1〜Shard3のPRIMARYと同居してるmongosを指定してました。結果的に、全てのクライアントが最初に記述されてるmonogos(Shard1のPRIMARYと同居してる)につなぎにいって、コネクションが枯渇していたと思われます。
そもそもmongosは、クライアントと同居させた方が良いようです。
mongos processes can run on any server desired. They may be run on the shard servers themselves, but are lightweight enough to exist on each application server.
という経緯があって、7月にはmongosを各クライアントと同じサーバで動作させることにしました。結果、今のところコネクション枯渇エラーは発生していません。
のようにmongosが死ぬことはありえるので、現状ではプロセス監視と自動起動で逃げています。この対応も不十分なので何とかしたいところ。
JavaのDriverに関する詳細はJava Driverのコネクションプールについて調べてみたもご参照下さい。
自動マイグレーションが止まらない
これはメリットでもありデメリットでもあります。
データ量が多くなければ自動マイグレーションは本当に便利で、すごく手軽にShardを追加できます。Picoの場合はデータ量とコレクションのオブジェクト数がそれなりに多い(7月時点でオブジェクト数は3.5億、データ量は150GB程度)ので、自動マイグレーションに頼ると新規でShardを追加したときは厳しかったです。
現時点では、自動マイグレーションのアルゴリズムはアクセス頻度ではなくあくまでデータ量でのバランシングなので、より効率的なデータ配置を行いたい場合は、自動マイグレーションをOFFにすることも必要かと思います(自動マイグレーションをONの状態で手動で移動することも出来ます。その場合は自動マイグレーションで、データが再び元のShardに戻されるケースもありえます)。
詳細は MongoDB Auto-Sharding at Mongo Seattle や オライリーから出版されているScaling MongoDBのBlancingのページをご参照下さい。
異なるバージョンのMongoDBが混在
これは完全に自分のオペミスでした・・・。今振り返ると、そのまま新しいバージョンにするという選択肢もあったんですが、調査が不足していて元のバージョンに戻すという対応を取りました。
1.6系から1.8系へのバージョンアップの方法についてはUpgrading to 1.8をご参照下さい。注意点としては、
1.8.x secondaries can replicate from 1.6.x primaries.
1.6.x secondaries cannot replicate from 1.8.x primaries.
ですね。PRIMARYを1.8系に変えた時点で、1.6系に戻すのは厳しいと思います。
バージョンアップでchunkサイズが変わった
検証したときは問題なかったんですが、本番環境で発生してしまいました。。。発生する条件がはっきりしないんですが、id:tm8r さんのchunkSizeではまる のエントリが関連してそうな気がします。おとなしく--chunksizeを起動時に渡すのが正解だったかも。
データの同期に失敗
サーバの入れ替え作業として、ReplicaSetの状態を
Member1 | PRIMARY |
Member2 | SECONDARY |
Member3 | SECONDARY |
Member1 | PRIMARY |
Member2 | SECONDARY |
Member3 | SECONDARY |
Member4 | SECONDARY |
Member5 | SECONDARY |
Member6 | SECONDARY |
Member4 | PRIMARY |
Member5 | SECONDARY |
Member6 | SECONDARY |
と変更していく手順で行おうとしていました。が、2番目の状態でメンバーの数が偶数となってしまい、かつMember4〜Member6が同期が取れない状態となり、PRIMARYが起動出来なくなるという自体になってしまいました。
Member1 | SECONDARY |
Member2 | SECONDARY |
Member3 | SECONDARY |
Member4 | still initializing |
Member5 | still initializing |
Member6 | still initializing |
詳細はMongoDBでReplicaSetにメンバーを追加/削除する方法と、その注意点 に書いてあります。こちらは完全に検証不足でした。。。いま考えると、Member4〜Member6のlocalのdbsを消して再起動をかければ良かったかも。
同じShardのmongodの2台がEC2インスタンスごと死亡
これはもうどうにもこうにも。EC2の問題なので・・・。3台1セットのReplicaSetであれば、2台同時に死ぬことは普通ない・・・はず。と思うしかないです。。。
mongodが落ちる
これは滅多にないんですが、とはいえたまにあります。1台だけならまだいい・・・と思いつつも、PRIMARYが落ちた場合はSECONDARYの同期が取れてないデータが存在してしまう可能性もあるので、怖さはあります。バージョン上がればもっと安定するかな・・・。
まとめ
バージョンの移行とかサーバの入れ替えとか、通常行わない作業でハマったケースが多かった感じです。今から最新のバージョンでやる分には、あまり問題にならないかと思います。mongod/mongosがたまに落ちる件はまだ怖いんですが。。。
MongoDB自体は、ReplicaSetやAuto-Shardingの仕組みを最初から備えていて、とっても素晴らしいプロダクトだと思います。インフラ担当がほとんどいない状態でも運用出来てるのは、これが大きいです。ドキュメント指向なので複雑なデータも扱えますし、ドキュメント内にインデックスを貼ったり、ドキュメントの一部を取得したり更新することも出来ます。
通常のRDBでは扱いづらいもの、個人的にはソーシャルゲーム系では結構向いてるんじゃないかなと思ってます。階層を持つようなデータはどうしてもRDBだと扱いづらいですし。ユーザが爆発的に増えた場合には自動マイグレーションが威力を発揮するかと。
そんなわけで、I love mongo、使ってることは全然後悔してないです!もっともっと安定させてあげたい!
余談
ちなみにこれ、LTで発表したネタ資料ですので・・・。いろいろ説明足らずなところがあって申し訳ありませんでしたm(_ _)m
余談その2
Picoのサービスは2010年3月からなので、もう1年半近く運用してます。当初は独自KVSで、MongoDBに移行したのは2010年9月だったようです。自分がJoinしたのが2011年1月からだったので、半年の運用と表現させて頂きました。