2011年12月17日土曜日

MongoDBを本格利用するために

MongoDB使ってますか?RavenDBのほうがいいですか?それともCassandraですか?いやいや、NoSQLなんて使わない派ですか?RDBよりも使い勝手のいいところがイロイロあると思うので、積極的につかてみてはどうでしょう。

先日MongoDBのSessionStateStoreに手を加えて、高速化してみたわけですが、そもそもMongoDBをどこに構築しておきましょう。自社内サーバー?DC内サーバー?いろいろ悩ましいところだと思いますが、ココは思い切ってAWS EC2に構築するのはどうでしょう。最近AzureでもOpennessでMongoDBが取り上げられてましたね。それもいいですけど、今回はEC2です。

おまたせしました。楽しいMongoDBの時間デス(1/5):企業のIT・経営・ビジネスをつなぐ情報サイト EnterpriseZine (EZ)

MongoDBも2になってからはジャーナルが標準だし、ReplicaSetとShardingもあるし、アクセス認証もかけれるしで、良い感じですよね!

がしかし!つい最近までは致命的な問題があったんです。認証使えるはずなのに、Sharding環境で認証をかけてるとC# Official Drivderが例外おきて接続できなくて、実質認証を使えないという問題。DC内ならいいけど、クラウドに持って行こうと思うと、これが非常に都合が悪い。パフォーマンスを考慮すると大変都合が悪かったです。

そもそもは、なんでMongoDBを運用環境に利用しようとしたか、ですけど、そんな話はどーでもいいですね。ちなみになんで運用環境に持って行こうと考えたかというと、SQLServerのミラーリングのコストが馬鹿にならなくなってきたから。あとログを1箇所に集約したかったっていう理由も大きい。イベントログめんどくね?フォワーディングするにしても、操作しにくいし。DBのマシン性能が低いっていう問題があったんだけど、そこに投資しないと解決出来ないってわけでも気がしたんですよね。違うアプローチで解決出来そうだとゴーストがささやいた。もちろん投資すれば一発解決。大人の解決方法です。でも、なんかNoSQLで解決できる気がしたんすよ。そういうことあるでしょ?

TraceListner into MongoDB
MongoDBにASP.NETのSessionを格納する
MongoDBにASP.NETのSessionを格納する - 完結編  

ASP.NETのセッションデータと、トレースログをSQLServer以外に保持したい。そのために必要なパーツは用意して、パフォーマンスとか可用性とか拡張性とか検証して行けそうだと感じたら、どこに構築しましょうか、ってことになりますよね。DC内に構築するのがネットワーク的にも近いし、効率いいのはそうなんですけど、んじゃサーバーどこから調達するのさー、ってなるし、よく分からないものに投資してくれろ、とは言いづらいしそもそも投資するならまずDBだろ、みたいな事になって行ったり来たり。むふー。とりあえずは、仮想マシン用意してその中にMongoDBの構築を行うっていうところでスモールスタートするわけですが、それも時限式。余裕ない。こうなったら、本格的にクラウドで構築するしかねー!MongoHQっていう選択肢も無いわけじゃないけど、いっその事、AWS EC2にがっつり構築するのがいいんじゃないかと、一人プロジェクトスタート。クラウド使ってるっていうとなんかカッコイイ気がするじゃない。

イロイロ試した結果、ReplicaSetとShardingでmongodインスタンスを6個(rsを3台ずつ2シャード)、mongosインスタンス4個、コンフィグインスタンス3個。MongoDBだけでまずは13個。それとDNSが2台。コンフィグ2台とDNS2台は相乗りにして全13台。DNSはAWS内部での名前解決に使う目的と、既存ドメインのサブドメインで外向きの名前解決用。既存のDNSの管理者権限なんて欲しくないし、弄りたくもないので、既存DNSにはゾーン委譲だけしてもらうようにして、AWS用のサブドメインを用意しました。その方が自分で好きなように制御出来るもんね!なぜmongosが4個なのかって?スモールスタートなら2個でいいじゃん!と思うところですが理由は別。

予算の関係もあって、すべてマイクロインスタンスで構築。なので、DC内からのアクセスでVPCは除外。VPNが簡単でよかったんだけど、そもそもDCにVPNルータを設置する余裕すらない。スペースと電源ね。大丈夫だとは思うけど、EC2がマイクロじゃないと予算が辛い。だってこの時点ではまだ自腹。そんなに稼いでませんから!

で、まぁ、今のMongoDBのバージョン(2.0.1)じゃShardingで認証が出来ないってところにたどり着いてガックリしてたわけです。

[#SERVER-3929] Arbitrary replica set authentication "need to login" errors. - MongoDB

しょうがないよね。できないものは出来ないと諦めて、IP制限で接続制限かけることにしました。アクセス経路はDCからAWSなので暗号化はしておきたい。でもVPCは厳しい。そうなるとIPSecかSSL tunnelか。ELBにSSL tunnel出来る機能があるので、それがいいなと思ってたんだけど、ELBはIP制限かけられない。インスタンスに届いた時のIPはELBのIPだし、SSL tunnelだとHTTPなわけでもないからX-Forworded-Forなんか無いし。そうなるとIPSecでマシン間接続の暗号化かってことになって、IPSecの設定の勉強から。認証できれば一気に解決なのにー、と思いつつできないものはしょうがない。

なので結局選択肢はなくIPSec。初めてIP セキュリティポリシー使いました。ウィザードの使い方をちゃんと理解すれば大丈夫だった。あとネゴシエーションのためにUDP500,4500開けるのを忘れずに。この話長いから省略。

ちなみにMongoDBにアクセスするすべてのマシンにIPSecを登録するのは大変なので、Delegateを利用してポートフォワード。コレはコレで懐かしい感じですね。NIFTYの時以来。

DeleGate Home Page (www.delegate.org)

やっと、経路がセキュアになって、IP制限をかけれるようにもなったので、EC2で構築したMongoDBへのパフォーマンステスト。ただ残念ながら、IPSecしないのに比べて随分遅い。4:3くらいの比率で遅い。暗号化のコストが発生するからmongosがヒーヒー言ってる...。

先ほどmongos4台用意したといったのには意味があって、外向き(IPSecで外部から接続する場合)と内向き(AWS内のMonogDB以外のインスタンスからの接続用、暗号化しなくていいもんね)でそれぞれ構築しないとパフォーマンスしんどいからです。なので、外向きはIPSec対応mongos、内向きは素のmongos。それぞれ2台ずつ用意して計4台。

IPSecを使ったら遅いのはCPUがパワー不足なのも原因だからインスタンス大きいの使うしかないのかなー、と思いつつもそれでもSQLServerに入れるよりは早いし、まぁ、いいかと。いつの日か先のMongoDBの不具合が改修された暁には再度設定しなおそうと思い、まずはこれで開始。

いろいろ大変だね。OpenSSL使って証明書を作ったり、Delegateでゲートウェイ用意したり、IPSecの接続環境作ったり、そもそもMongoDBの環境作ることも含め、やること山盛り。それらのHowTo書こうと思うと大変面倒なので全てまとめて省略!勉強になったよ。MongoDBでReplicaSet+Shardingでの認証のやり方(ReplicaSetで個別にPRIMARYにユーザー登録して、mongos起動後configサーバーにもユーザー登録、最後にauthとkeyFile指定してサービス化。ちなみにそこまではコンソール起動でちょこちょこ調整しながら作業しました)がわかりにくかった。これまでのバージョンでうまくいってない部分だったみたいだからやむなし。インフラ屋って大変ね。

OpenSSL: The Open Source toolkit for SSL/TLS

今年ももう十分やりきっただろ。と、思った矢先にMongoDB2.0.2リリースのお知らせ。

Downloads – MongoDB

数日前にRC2が出たときには今年はもうないな、と思ってたのに。ウズウズ。ワクワク。ちなみにRCで先の不具合が解消されてたのは確認済みだったので、リリースをひたすら待つだけだったんですけど、まさかこのタイミングで出てくるとはねー。

こうなるとELBを利用してSSL tunnel(ELBではSecureTCPっていう名前)を利用する環境を用意してしまおうじゃないかとなりましょう。ReplicaSet+Shardingで認証かけれれば、後は経路の問題だけだし、何よりELBで暗号化復号化してくれればmongosが通信に専念すればいい状態になるし、更にはELBがラウンドロビンでmongosを選んでくれるから、パフォーマンスは大幅向上。1.25倍(2倍近くさばける時もある)くらい早くなりました。ELBだとアクセスが増えると受け口を自動でスケールしてくれるので、負荷がもっと高くなると、5分くらいで自動でよしなにしてくれるらしい。5分だっけ?そこはいいか。そうするとIPSec用mongosは用なし。さらにEIPでグローバルも不要。DNSにELBのCNAMEを登録すればいいだけになって更にお買い得。

運用の目処もたち、Reserved Instanceで見積もったり(超間違えたけど)して、最終的にやっと会社が払ってくれるようになって一安心。DBもWebもある程度はAWSに持っていっちゃう予定だけど、最終形態はDCとクラウドのハイブリッドが良い感じに思えますが、一般的にはどうなんだろ。

今はまだテスト環境のセッションストアと、トレースログの取得だけにしか使ってないけど、徐々に全てのトラフィックをDC内のMongoDBからAWSのMongoDBに変更していく予定です。どーなるかなー。楽しみだなー。

せっかくなのでPPT用の素材を使って今回の構成図を書いてみたよ。

MongoDB 2.0.1でIPSecの時

スライド1

MongoDB 2.0.2でELBの時

スライド2

あは。センスないー。素材があってもコレじゃ...。なんとなくでも伝わるといいな。mongosからReplicaSetをShardingとして参照するように設定してるのをうまく表現できませんでした...。

ところで、CloudWatchって数値高めに出てない?実際ログインして直接パフォーマンス見てみると、CloudWatchで表示されるほど高くないんだけどなー。なんだろ。そんなもの?

dotnetConf2015 Japan

https://github.com/takepara/MvcVpl ↑こちらにいろいろ置いときました。 参加してくださった方々の温かい対応に感謝感謝です。