読者です 読者をやめる 読者になる 読者になる

中年engineerの独り言 - crumbjp

LinuxとApacheの憂鬱

またまたmongo-php-driver問題

前回の困ったちゃんをまた直しました・・・

また一言!

mongo-php-driver はマトモに動かん!!

いつの間にかmasterブランチにメモリリークが組み込まれてる!!
→ v1.2ブランチは無事

なんだってこんなに頻繁にメモリリークをぶっ込むんだろうか?

ったく・・・

まあそれは置いといて、今回は障害発生時のコネクションの話。

唐突に!

MongoDBはC-Pシステムである。

この辺が詳しい

CAP定理

  • 一貫性(Consistency)
  • 可用性(Availability)
  • 分割耐性(Partition Tolerance)

http://www.hyuki.com/yukiwiki/wiki.cgi?BrewersCapTheorem

 MongoDBは、一貫性を諦めておらず可用性(availability)を妥協している。
 これは書き込みは常にマスターが行う事でこれを実現している。

  プライマリDOWNの際は自動的にセカンダリが昇格するものの
  ある程度のタイムラグが発生しその間書き込みが不可能となる。

よって、、

 MongoDBを利用するアプリケーションはあらかじめ
  『障害時には【ある程度】接続できない時間がある』
 事を考慮して作らなければならない。

 そうは言っても
  ある程度!ってどの程度!?
   1.   5秒?
   2.  30秒?
   3.   1分?
   4.   3分?
   5.  10分?

 大体、どの程度のDOWNを見込んだら良いのか解らなければ、アプリも書けないよ!!

 というのが今回のお題です。

 皆さんどの位まで許せますか?

 僕は2.かギリギリ3.なんですよね


 お題にしている以上、想像つくとは思いますが・・・思ったより長いのです。
 mongo-php-driverでは、、
  3.と4.の間です!

mongo-php-driver with replica-set

 mongo-php-driverは60秒毎にreplica-setの構成チェック(rs_ping)が走っている。

 ※赤字はmongod側の挙動

プライマリDOWN時の挙動

   1. recplica-setのプライマリDWON
     recplica-setは一時的にプライマリ無しの状態になる。
   2. (リクエストを送るプライマリが無い為) 書き込みリクエストが失敗し始める。
     Error: couldn't determine master
     次のrs_pingまで続く
   3. revote後、新しいプライマリが決定される
   4. 60秒毎のrs_pingが行われ新しいプライマリが判明する。
   5. 100秒前後で復旧

マスタ切り替え時の挙動

   1. プライマリがSTEP DOWNする
     recplica-setは一時的にプライマリ無しの状態になる。
   2. (リクエストがセカンダリに飛ぶ為) 書き込みリクエストが失敗する。
     Error: not master
     次のrs_pingまで続く
   3. revote後、新しいプライマリが決定される
   4. 60秒毎のrs_pingが行われ新しいプライマリが判明する。
   → ハズなのだが、何故かcouldn't determine masterとなる。(10秒ほど)
   5. 110秒前後で復旧

もう少し長いことも!

  rs_pingが走るタイミングによっては
  復旧まで倍近い200秒前後かかる場合もあります。

  更に、PHPapache(prefork)で利用する事が多いと思いますが
  上記の処理がhttpdプロセス毎に行われるので(リクエストが極端に少ない場合など)
  全プロセスにreplica-setの変更が行き渡るまでに、更に時間がかかります。

じゃあどうするのか?

 解は2つあります。

mongos導入

 多数のhttpdプロセスが個々にreplica-setの変更に追従するのは時間もコストもかかるので
 思い切って(shardcollectionはせずに)sharding構成にしてmongosを導入。

 システム構成的にも綺麗になってお勧めです

 メリット:
  障害周りの複雑な処理をmongosに丸投げして
  mongo-php-drikverはローカルホストのmongosと安定したコネクションを維持できます。

  mongodへのコネクション数も半分以下に減らせます。

  buggy! なmongo-php-driverに負担を掛けずに済む!!

 デメリット:
  mongod(config server)を立てる必要がある。
  運用が面倒くさい・・・
 
  mongosはmongosでちょっと問題がある。

mongo-php-driverを直す

 でも運用が面倒な人(自分)の為に直しました。

 リクエスト失敗時に60秒待たずにrs_pingを投げてしまう。

 今回は5秒毎に投げる事にしました。
 pull-request

 これでMongoDBの構成変更に5〜10秒程度で追従できます。
 無事取り込まれると良いのだけど・・・
 それまでは、こちらでメンテしてます。
 github