6

A (3.8M ドキュメント) と B (1.7M ドキュメント) の 2 つのコレクションがあります。

シェルから実行する PHP スクリプトがあります。

  1. A の各レコードをループします
  2. ~60% の確率で、B で findOne を実行します (_id を使用)
  3. いくつかの基本的な計算を行い、php 配列を作成します

a 内のすべてのドキュメントのループが完了すると、次のようになります。

4) php 配列をループする

5) コレクション C に upsert

(1) の間、私は一貫して次のように取得します: PHP Fatal error: Uncaught exception 'MongoCursorException' with message 'Cursor not found' 最後に処理されたアイテムは #8187/3872494 でした。

real    1m25.478s
user    0m0.076s
sys     0m0.064s

コードを変更せずに再度実行すると、アイテム#19826 / 3872495で例外がスローされました

real    3m19.144s
user    0m0.120s
sys     0m0.072s

繰り返しますが、#8181 / 387249

real    1m31.110s
user    0m0.036s
sys     0m0.048s

はい、私は例外をキャッチできる (そしておそらくキャッチすべき) ことを認識しています...しかし...なぜスローされているのでしょうか? 特に、データベースへのこのような異なる経過時間/深さで。

それが役立つ場合、私のセットアップは 3 ノードのレプリカ セット (2+arb) です。セカンダリをオフラインにして、プライマリのみを実行してみました。同じ結果 (処理された結果の数と時間は異なりますが、常に Cursor Not Found 例外がスローされます)。

4

3 に答える 3

10

はい、私は例外をキャッチできる(そしておそらくそうすべきである)ことを理解しています...

はい、これは間違いなく最初に行うことです。例外が発生する正当な理由は何十もありますか? プライマリがオフラインになり、到達不能になるとどうなると思いますか?

……なんで投げられるの?

考えられる理由はいくつかありますが、表示されているエラー コードに切り込みましょう。

  • 公式の PHP ドキュメントはこちらです。
  • そのページからの引用:ドライバーはデータベースからさらに結果を取得しようとしましたが、データベースにはクエリの記録がありませんでした。これは通常、サーバー側でカーソルがタイムアウトしたことを意味します...

MongoDB PHP ドライバーには、2 つの異なるタイムアウトがあります。

  • 接続タイムアウト
  • カーソルタイムアウト

カーソルのタイムアウトに達しています。DBに接続できますが、クエリは「時間切れ」です。

考えられる修正:

  1. カーソルのタイムアウトを延長します。または、ゼロに設定して永久に存続させることもできます。
  2. このジョブをバッチで実行します。A から最初の 1000 を取得し、_idsそれらを処理してから、処理したことを示します。次に_ids、最後の実行よりも次の 1000 を取得します。

例外の処理とともに#2をお勧めします。これらで問題が完全に解決されなくても、問題を切り分けて軽減するのに役立ちます。

于 2011-07-24T07:51:52.737 に答える
4

私はそれが遅いことを知っています。これはあなたの解決策ではないかもしれませんが、 immortal() を使用してみてください。Gates VP が指摘したように、このページでは例外について説明します。

ドライバーはデータベースからさらに結果を取得しようとしましたが、データベースにはクエリの記録がありませんでした。これは通常、サーバー側でカーソルがタイムアウトしたことを意味します。非アクティブ状態が数分間続くと、データベースはカーソルを強制終了します (これを防ぐ方法については、 MongoCursor::immortal()を参照してください)。

timeout() と immortal() が異なるため、このページに到達した他のユーザーの説明全体を投稿すると思いました。timeout() は、応答を待つ時間を設定します。immortal() は、非アクティブによるカーソルの停止を拒否します。

于 2011-10-18T06:40:09.350 に答える
0

メモリ制限の問題である可能性があります。より多くのメモリを提供して試してみて、結果が変わるかどうかを確認してください。これは -d オプションで行うことができます: php -d memory_limit=256M yourscript.php

これは大量のドキュメントであり、かなり大きなオブジェクトの配列を作成しているように思えます。実行時にメモリ割り当てをプロファイルするために使用できる memory_get_usage() のようなさまざまな php 関数や、xdebug や zend が提供する拡張機能のデバッグにも使用できます。

于 2011-07-24T07:49:27.393 に答える