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

中年engineerの独り言 - crumbjp

LinuxとApacheの憂鬱

荒ぶるmongos様

Sharding構成で苦しんだ時の状況

現在mongosのコードを解析中なので、状況だけ。
ごく一般的な利用方法だと思うのだけどShardingは取扱いに注意が必要。

システム構成

実際はMongoDBサーバも沢山あってShardingを構成しているのですが
 今回の現象は1台でも同じ事なので1台として表現します。

  • Webサーバ x いっぱい
  • MongoDBサーバ
    • mongod
        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 まで回収してくれました。

maxConn

mongosのこの設定はクライアント側(※2)に効く様です。

今回のケースではhttpd数はMaxClientその他によって完全に制御できるので意味がありません。

また

この設定が効いてしまうという事はサービス障害httpdの必要とするクエリーが失敗するという事)
を意味するので、トチ狂ったクライアントを見捨てる意味で設定はするモノの実際は効いて欲しくありません。

問題点

一番重要な点は

MongoDBが高負荷になった時みんなで袋叩きにして瞬殺してしまう

(一斉に新コネクションを張りまくり、ますます負荷を掛けてしまう)

根本的には、ほとんどの分散システム構築で共通する、『弱い所に負荷が集中』する問題な気がします。

対処無しか?

調査中

mongosのコネクションプール制御をもっと賢く出来ないものか?

→※3側が諦めたら※2側も閉じる的な動作がほしい!

[> 続き