2013-12-20 9 views
7

現在、MongoDB内のCapped CollectionsとTailable Cursorを調べて、通知のキューイングシステムを作成しています。しかし、実行時に気付いた単純なLinqPadテスト(下のコード)を作成した後、Mongoは、レコードを挿入していなくても、利用可能なリソースがなくなるまで常にメモリを割り当てます。この割り当ては、すべてのシステムRAMが使用されるまで続きます。その時点でMongoは単に応答しなくなります。MongoDB 2.4.8キャッピングされたコレクションと利用可能なすべてのメモリを消費するカーソル

私たちはCapped CollectionsとTailable Cursorsが新しくなったので、バグを提出する前に明白な何かを見逃していないことを確認したかったのです。

注:以下のコードでは、ジャーナリングをオン/オフして同じ結果を試してみました。

  • プラットフォーム:のWindows Server 2012の64ビット
  • MongoDBの:バージョン2.4.8 64ビット
  • ドライバー:公式C#の10genのv1.8.3.9

Linqpadスクリプト

var conn = new MongoClient("mongodb://the.server.url").GetServer().GetDatabase("TestDB"); 

if(!conn.CollectionExists("Queue")) { 

    conn.CreateCollection("Queue", CollectionOptions 
     .SetCapped(true) 
     .SetMaxSize(100000) 
     .SetMaxDocuments(100) 
    ); 

    //Insert an empty document as without this 'cursor.IsDead' is always true 
    var coll = conn.GetCollection("Queue"); 
    coll.Insert(
     new BsonDocument(new Dictionary<string, object> { 
      { "PROCESSED", true }, 
     }), WriteConcern.Unacknowledged 
    ); 
} 

var coll = conn.GetCollection("Queue"); 
var query = coll.Find(Query.EQ("PROCESSED", false)) 
    .SetFlags(QueryFlags.AwaitData | QueryFlags.NoCursorTimeout | QueryFlags.TailableCursor); 

var cursor = new MongoCursorEnumerator<BsonDocument>(query); 

while(true) { 
    if(cursor.MoveNext()) { 
     string.Format(
      "{0:yyyy-MM-dd HH:mm:ss} - {1}", 
      cursor.Current["Date"].ToUniversalTime(), 
      cursor.Current["X"].AsString 
     ).Dump(); 

     coll.Update(
      Query.EQ("_id", cursor.Current["_id"]), 
      Update.Set("PROCESSED", true), 
      WriteConcern.Unacknowledged 
     ); 
    } else if(cursor.IsDead) { 
     "DONE".Dump(); 
     break; 
    } 
} 
+0

実行中にdb.currentOp()を実行して結果をポストできますか?あなたはまた、実行をカバーするmongodログファイルを投稿できますか? –

+0

同じ問題が発生しました... mongoDBはこれが実行中にoplogをRAM に保持しているようです。 情報のために、私は単一のマシンを使用して、複製機能 を追加します。 ここに私のcurrentOpとログがあります: https://dl.dropboxusercontent.com/u/853035/currentOp.txt https://dl.dropboxusercontent.com/u/853035/log.txt –

+0

私はそれを発見しましたメモリ使用量は、初めてMoveNextに入る約2.4GBです。最初のドキュメントが返された後、それは1.2GBに落とされ、2番目のドキュメントの後に元の値に戻ります???ここで画像を見てください:https://dl.dropboxusercontent.com/u/853035/memory_usage.png –

答えて

5

問題の解決策を見つけたようです。

上記のコードでは問題がクエリを中心に展開:

Query.EQ("PROCESSED", false) 

私はこれを削除し、文書のIDに基づいて、クエリでそれを交換した場合、メモリ消費量の問題が姿を消しました。さらに反映すると、cursor.MoveNext()は常に次の新しいドキュメント(存在する場合)を返すので、この "PROCESSED"プロパティはクエリでは必要ありません。上記のコードに基づいてリファクタリングされたLinqPadスクリプトを紹介します....

var conn = new MongoClient("mongodb://the.server.url").GetServer().GetDatabase("TestDB"); 

if(conn.CollectionExists("Queue")) { 
    conn.DropCollection("Queue"); 
} 

conn.CreateCollection("Queue", CollectionOptions 
    .SetCapped(true) 
    .SetMaxSize(100000) 
    .SetMaxDocuments(100) 
    .SetAutoIndexId(true) 
); 

//Insert an empty document as without this 'cursor.IsDead' is always true 
var coll = conn.GetCollection("Queue"); 
coll.Insert(
    new BsonDocument(new Dictionary<string, object> { 
     { "PROCESSED", true }, 
     { "Date", DateTime.UtcNow }, 
     { "X", "test" } 
    }), WriteConcern.Unacknowledged 
); 

//Create query based on latest document id 
BsonValue lastId = BsonMinKey.Value; 
var query = coll.Find(Query.GT("_id", lastId)) 
    .SetFlags(QueryFlags.AwaitData | QueryFlags.NoCursorTimeout | QueryFlags.TailableCursor); 

var cursor = new MongoCursorEnumerator<BsonDocument>(query); 

while(true) { 
    if(cursor.MoveNext()) { 
     string.Format(
      "{0:yyyy-MM-dd HH:mm:ss} - {1}", 
      cursor.Current["Date"].ToUniversalTime(), 
      cursor.Current["X"].AsString 
     ).Dump(); 
    } else if(cursor.IsDead) { 
     "DONE".Dump(); 
     break; 
    } 
} 
0

ここには - その追加クエリはありません。

最初のMoveNextメソッドは、問題が存在するレコードを返さない場合は、次のいくつかのより多くの調査の後

(実際には非常に多くのMORE)私 問題はこのようになりました。 クエリの種類は問われません。 コレクション内のエントリの数は関係ありません。

最後のエントリを返すクエリを最初の という結果に変更すると、すべて正常に動作します。 これを既に知っています...

最初にコレクションにあるすべてのレコードが最初に取得されるため、上の例は成功します。

関連する問題