0

データを取得する方法として、MongoDB をキューとして使用し、PHP-Queue を使用しています。これは POC であり、私は OSX マシンで実行しています。Mongo のパフォーマンス、つまり findmodify 関数のパフォーマンスが非常に遅いことがわかります。私は PHP 側で一連のテストを行いましたが、PHP 処理は時間の約 5% しか占めていません。たとえば 10,000 件のメッセージで Mongo コレクションをいっぱいにすると、3 ~ 5 秒程度ですぐにいっぱいになります。でも、空にすると250秒くらいかかります。このうちPHP側はわずか10秒ほど。mongod プロセスをチェックすると、約 60MB を超えることはありませんが、CPU は全体で 90% 以上スパイクします。コレクションのインデックスを作成しました。以下は、メッセージ データとインデックスのサンプルです。

メッセージの例 (これは、キュー内の 10,000 件の同様のメッセージの 1 つです):

{
  "_id": ObjectId("526c47d5c5008c1d5cd63ef8"),
  "payload": {
    "0": {
      "EVENT_HEADER_KEY": NumberInt(9094775),
      "event_name": "Account Change",
      "source_name": "Work",
      "event_category_name": "Complex Events",
      "EVENT_TIMESTAMP": "Aug 17 2013 12:00:00:000AM",
      "PARENT_HEADER_KEY": null,
      "year": NumberInt(2013),
      "month": NumberInt(10),
      "Company_Name": "ACME PRODUCTS, INC.",
      "Company_Email": "blabla",
      "Company_Phone": "555-555-5555",
      "First_Name": "Jon",
      "Last_Name": "Doe",
      "ID_NUMBER": "111111111",
      "created_by": "Load Job Name",
      "created_at": "Oct 18 2013 04:07:31:140PM",
      "product_analytical_category": "blabla",
      "_Event_Type": "blabla",
      "CUSTOMER_ID": "111111111"
   }
 },
  "running": false,
  "resetTimestamp": ISODate("2038-01-19T03:14:07.0Z"),
  "earliestGet": ISODate("1970-01-01T00:00:00.0Z"),
  "priority": 0,
  "created": ISODate("2013-10-26T22:53:09.440Z")
}   

自動的に作成されたと思われるこのコレクションのインデックス:

{
   "_id": NumberInt(1)
}

mongo.log を確認すると、キューを空にすると、約 70 のメッセージに対してメッセージあたり約 1 ミリ秒しかかからず、opid が変更され、300 ~ 900 ミリ秒の遅延が発生してから続行することがわかります。メッセージあたり約1ミリ秒の同じペースで新しいopid。これらの opid の変更は、250 秒の処理時間のうち約 50 ~ 100 秒を占めているため、さらに多くの処理が行われています。

mongo.log からの抜粋:

**Sat Oct 26 15:15:25.189** [conn4] warning: ClientCursor::yield can't unlock b/c of recursive lock ns: test.abe top: { **opid: 20064**, active: true, secs_running: 0, op: "query", ns: "test", query: { findandmodify: "abe", query: { running: false, earliestGet: { $lte: new Date(1382825725143) } }, update: { $set: { resetTimestamp: new Date(1382825785000), running: true } }, fields: { payload: 1 }, sort: { priority: 1, created: 1 } }, client: "127.0.0.1:53045", desc: "conn4", threadId: "0x119024000", connectionId: 4, locks: { ^: "w", ^test: "W" }, waitingForLock: false, numYields: 0, lockStats: { timeLockedMicros: {}, timeAcquiringMicros: { r: 0, w: 3 } } }

**Sat Oct 26 15:15:25.190** [conn4] warning: ClientCursor::yield can't unlock b/c of recursive lock ns: test.abe top: { **opid: 20064**, active: true, secs_running: 0, op: "query", ns: "test", query: { findandmodify: "abe", query: { running: false, earliestGet: { $lte: new Date(1382825725143) } }, update: { $set: { resetTimestamp: new Date(1382825785000), running: true } }, fields: { payload: 1 }, sort: { priority: 1, created: 1 } }, client: "127.0.0.1:53045", desc: "conn4", threadId: "0x119024000", connectionId: 4, locks: { ^: "w", ^test: "W" }, waitingForLock: false, numYields: 0, lockStats: { timeLockedMicros: {}, timeAcquiringMicros: { r: 0, w: 3 } } }

**Sat Oct 26 15:15:25.507** [conn4] warning: ClientCursor::yield can't unlock b/c of recursive lock ns: test.abe top: { **opid: 20141**, active: true, secs_running: 0, op: "query", ns: "test", query: { findandmodify: "abe", query: { running: false, earliestGet: { $lte: new Date(1382825725501) } }, update: { $set: { resetTimestamp: new Date(1382825785000), running: true } }, fields: { payload: 1 }, sort: { priority: 1, created: 1 } }, client: "127.0.0.1:53045", desc: "conn4", threadId: "0x119024000", connectionId: 4, locks: { ^: "w", ^test: "W" }, waitingForLock: false, numYields: 0, lockStats: { timeLockedMicros: {}, timeAcquiringMicros: { r: 0, w: 3 } } }

これは、これらの 10,000 メッセージのログ全体で基本的に同じです。メッセージごとに 1 ミリ秒しかかからない findandmodify() の長いシーケンスがあり、その後 opid が変更され、ほぼ 1 秒かかる遅延が発生します。これが何か重要なことを示しているかどうかはわかりませんが、私は Mongo を初めて使用し、有望と思われるパターンを見つけようとしています。

アップデート:

このクエリは、フィールド 'running' が false であることを確認し、さらに EarlyGet フィールドがエポック (1-1-1970) より新しいことも確認します。これらのフィールドにインデックスを追加しても無駄でした。これらのフィールドはコレクション内のすべてのメッセージ ('false' および 1970 年 1 月 1 日) で同じであるため、それらのインデックス作成によってクエリ時間が増加するだけである可能性があります。これを適切に機能させるために何をすべきかわかりません。1970 年 1 月 1 日よりも新しい最初のレコードを取得する必要があるようですが、明らかに Mongo はまだコレクション全体を処理しているため、クエリが遅すぎて実用的ではありません。さらに、選択基準がない場合でも、応答時間は 202 秒です。これは高速ですが、許容範囲ではありません。また、「yield can't unlock b/c of​​ recursive lock ns:」というメッセージも表示されます。

4

2 に答える 2

4

findAndModifyコマンドのクエリおよびソート部分に使用される非常に重要なインデックスがありません。そのインデックスがないと、各コマンドでコレクション全体をスキャンし、結果セット全体をソートする必要があり、非効率的です。「コレクションにインデックスを付けました」と言いましたが、常に存在し、役に立たない「_id」インデックスについてのみ言及しました。

推奨事項: 少なくとも、実行中のフィールドと EarlyGet に複合インデックスを追加します。インデックスに並べ替えフィールドを含めると役立つ可能性がありますが、各クエリに一致するドキュメントの数は比較的少ないと予想されるため、メモリ内並べ替えはそれほど重要ではない可能性があります。

指示:

db.abe.ensureIndex({running:1, earliestGet:1})

コメントの議論で、実行中の EarlyGet インデックスはまったく選択的ではないことが判明しましたが、最初に一致したドキュメントのみを取得するように並べ替えているため、代替手段は並べ替え列にインデックスを追加することです。

指示:

db.abe.ensureIndex({ priority: 1, created: 1 })
于 2013-10-26T23:51:32.170 に答える
1

より詳細な説明がなければ、変更フェーズで正確に何をしているのか、決定的な答えを出すのは困難です。ログから判断すると、次のような更新を行っているようです。

db.abc.findAndModify(
    query: { running: false, earliestGet: { $lte: new Date(1382825725143) } },
    update: { $set: { resetTimestamp: new Date(1382825785000), running: true } }
)

earliestGetフィールドとフィールドにはインデックスがありませんrunning。カーディナリティが低いため、インデックスを追加しrunningても実際の違いはありませんが、インデックスが不足してearliestGetいると実際の問題になる可能性があります。

warning: ClientCursor::yield can't unlock b/c of recursive lock ns:この質問を見ることができるメッセージについて: MongoDB: Geting "Client Cursor::yield can't unlock b/c of​​ recursive lock" warning when use findAndModify in two process instances

于 2013-10-26T23:52:03.640 に答える