遅いクエリを実行すると、MongoDB PHP ドライバー (v1.3) でやや奇妙な動作が発生します。リクエストが遅いときにドライバーが接続を開き続けるように見えますが、その理由が完全にはわかりません。たぶん、ここでいくつかの提案があります。
最初にいくつかの事実を次に示します。
- 単一の Ubuntu 13.04 サーバーで実行される Web サイトとデータベース
- サーバーはハイエンドの 8 コア 16GB RAM サーバーです
- MongoDB v2.2.4
- ウェブサイトは PHP 5.4 を実行しています
- Web サーバーとしての Apache 2
- PHP Mongo ドライバー 1.3.x (最新の 1.3 である必要があります)
- ウェブサイトは Doctrine ODM を使用しています
- Web サイトには常に約 50 ~ 100 人の同時ユーザーがいます
- ulimit オープン ファイル (ulimit nofile) = 64000
1 日に 1 回、Memcache レコードの有効期限が切れ、低速のクエリが実行されます。これにより、PHP は MongoDB に対して最大 800 の接続を開きます (通常、ログによると、10 の開いている接続があります)。私たちのウェブサイトはほぼ完全に Memcached であるため、データベースには他に大きな負荷はありません。800 の開いている接続により、Web サイトの最初の読み込み時間は 30 秒になり、後でいくつかのタイプの MongoExceptions (接続が多すぎる/ソケット例外) がスローされます。
これは、group by を使用した見苦しいクエリです。完全に明確にするために、このクエリが遅くてばかげていることを理解しており、本日、このクエリを削除します。なぜそれがウェブサイト全体を台無しにするのかは明らかではありません. Doctrine を抽象化レイヤーとして使用しますが、ログによると、これは 200,000 ドキュメント データベース (ドキュメントあたり 3 フィールド: id/product/date) に対する実際のクエリです。
{"group":true,"keys":{"product":1},"initial":{"count":0},"reduce":"function (obj, prev) { prev.count++; }","options":[],"db":"Orders","collection":"History"}
クエリが完了すると、その結果が Memcache に 24 時間書き込まれます。したがって、すべての新しいリクエストは、MongoDB からではなく、Memcache から取得します。それでも、約 800 の接続に固執し、問題は解決せず、Web サイトはしばらくすると応答しなくなります。これらの 800 の接続を開くには、約 10 分かかります。
典型的な競合状態のように感じます。クエリは、この負荷でこのサーバーで競合状態を実際に引き起こすほど重く感じません。というか、あってはならない感じです。
さて、質問は次のとおりです。
- PHP が非常に多くの接続を開き続けるのはなぜですか?
- MongoDB がこれを処理できないのはなぜですか (それほど大きな問題ではないはずですよね?)
- 私たちが何をすべきかについて他に提案はありますか?
- これを解決するには、接続とクエリにタイムアウトを設定する必要がありますか?
私がこれを尋ねる理由は、私たちのウェブサイトが非常に急速に成長しており、将来的にトラフィックと MongoDB の負荷が大幅に増加すると予想しているからです。
よろしくお願いします!