我们目前正在探索MongoDB中的Capped Collections和Tailable Cursors来创建一个通知排队系统。但是,在创建一个简单的LinqPad测试(下面的代码)后,我们注意到在运行时,Mongo不断分配内存,直到没有更多可用资源,即使我们没有插入任何记录。这种分配一直持续到使用所有系统RAM为止,此时Mongo只是停止响应。
由于我们是Capped Collections和Tailable Cursors的新手,我想确保在提交错误之前我们没有错过任何明显的内容。
注意:我们尝试使用以下代码打开和关闭日记,但结果相同。
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 :(得分:5)
我似乎找到了问题的解决方案!!
上述代码中的问题围绕查询:
Query.EQ("PROCESSED", false)
当我删除它并将其替换为基于文档ID的查询时,内存消耗问题就消失了。在进一步思考时,查询中不需要这个“PROCESSED”属性作为cursor.MoveNext()将始终返回下一个新文档(如果有的话)。下面是基于上面代码重构的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;
}
}
答案 1 :(得分:0)
同样在这里 - 没有那个额外的查询。
经过多次调查(实际上非常多)我 发现问题看起来像这样:
如果第一个MoveNext没有返回记录,则问题存在。 查询是什么类型并不重要。 收集中有多少条目并不重要。
如果更改查询,则将最后一个条目作为第一个条目返回 结果一切正常。你可以丢弃这个 已经知道了......
上面的示例成功,因为您最初获得了集合中已有的所有记录。