荒ぶるmongos様
Sharding構成で苦しんだ時の状況
現在mongosのコードを解析中なので、状況だけ。
ごく一般的な利用方法だと思うのだけどShardingは取扱いに注意が必要。
システム構成
実際はMongoDBサーバも沢山あってShardingを構成しているのですが
今回の現象は1台でも同じ事なので1台として表現します。
WEB Servers | MongoDB Server ---------------------------------+ SERVER-1 | ※3 +----------+ | +-----------+ [httpd]-------->| |※2 | ※1 | | [httpd]-------->| +------------->| | [httpd]-------->| +------------->| | [httpd]-------->| +------------->| | [httpd]-------->| +------------->| | [httpd]-------->| mongos +------------->| | [httpd]-------->| +------------->| | [httpd]-------->| : | | [httpd] : | : | | [httpd] : | +------------->| | [httpd]-------->| | | | | +----------+ | | mongod | ---------------------------------+ | | SERVER-2 | | | +----------+ | | | [httpd]-------->| | | | | [httpd]-------->| +------------->| | [httpd]-------->| +------------->| | [httpd]-------->| +------------->| | [httpd]-------->| +------------->| | [httpd]-------->| mongos +------------->| | [httpd]-------->| +------------->| | [httpd]-------->| : | | [httpd] : | : | | [httpd] : | +------------->| | [httpd]-------->| | | | | +----------+ | | | ---------------------------------+ | | : | | | : | | | ---------------------------------+ | | SERVER-N | | | +----------+ | | | [httpd]-------->| | | | | [httpd]-------->| +------------->| | [httpd]-------->| +------------->| | [httpd]-------->| +------------->| | [httpd]-------->| +------------->| | [httpd]-------->| mongos +------------->| | [httpd]-------->| +------------->| | [httpd]-------->| : | | [httpd] : | : | | [httpd] : | +------------->| | [httpd]-------->| | | | | +----------+ | | | ---------------------------------+ | | +-----------+
mongod の接続制限は20000コネクションまで※1
割と簡単に溢れます
状況
まず
Webサーバの数(N)が増えれば、※1の数がいずれ20000に到達するのは仕方がない。
それはシステムの限界という事で良いのだが、Nが幾つで限界なのか?が問題。
20000 / 50(MaxClient) = 400 なので、200以上を期待したいのだが・・・
実際は80にも満たない状態で溢れる。(条件次第では10でも駄目)
せめてhttpd->mongos(※3)の数とmongos->mongod (※2)の数には、ある程度予測可能な相関関係が欲しいのだが・・・
通常運転
MaxClient 50 => httpdプロセス数50 = ※3数=50の場合
jmeter等で普通に負荷を掛けていっても ※2は55以下に収まる。
恐らく、mongosはhttpdからの要求毎に自分の抱えているコネクションプールを探索し
利用できるコネクションが無かった場合に新たなコネクションを作成するのだろう。
クエリータイムアウト
httpd->mongos(※3の部分)のリクエストはオンライン処理で通常タイムアウト設定をする。
例>
$col->update(array('_k' => $key),$rec,array(f'timeout' => 500));
なんらかの理由で、MongoDBの応答が遅くなった場合
※3はタイムアウトしコネクションは切られる。
しかし、mongos->mongod(※2)側の接続は維持される模様。
タイムアウトしたhttpdは、ブラウザ側にはエラーを返してしまうが
また次のHTTPリクエストを受け、新たにhttpd->mongos(※3)コネクションを張る。
よって
※3は50で変わらないまま、※2が何処までも増加していく。
再現実験
MongoDBサーバをdd等で負荷を掛けて行くと応答が遅れる。
これにより確かにmongos->mongod(※2)のコネクション数が際限なく上がっていく事を確認した。
その後
ドキュメントに寄ると、mongosは一旦抱えたコネクションは解放しないらしい。
http://docs.mongodb.org/manual/faq/sharding/
[Why does mongos hold connections?]コネクション解放したけりゃmongos再起動せよ。
しかし実際はmongosのログに以下の様な行が出て、ある程度は解放される模様。
[PeriodicTask::Runner] task: DBConnectionPool-cleaner took: 102ms
実験中では 550 => 59 まで回収してくれました。
問題点
一番重要な点は
MongoDBが高負荷になった時みんなで袋叩きにして瞬殺してしまう
(一斉に新コネクションを張りまくり、ますます負荷を掛けてしまう)
根本的には、ほとんどの分散システム構築で共通する、『弱い所に負荷が集中』する問題な気がします。
対処無しか?