当前位置: 首页 > 知识库问答 >
问题:

MongoDB 2.4.8封顶集合和可裁剪光标消耗所有内存

夏侯枫
2023-03-14

我们目前正在探索MongoDB中的上限集合和可跟踪游标,以创建通知排队系统。然而,在创建了一个简单的LinqPad测试(代码如下)后,我们在运行时注意到,Mongo不断分配内存,直到没有更多的可用资源,即使我们没有插入任何记录。这种分配一直持续到所有系统RAM被使用,此时Mongo简单地停止响应。

由于我们还不熟悉封顶系列和可定制游标,所以我想确保在提交bug之前,我们没有错过任何明显的东西。

注意:我们尝试了下面的代码,打开和关闭日志记录,结果相同。

  • 平台: Windows Server 2012 64bit
  • MongoDB:版本2.4.8 64bit
  • 驱动程序:官方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;
    }
}

共有2个答案

干鑫鹏
2023-03-14

这里一样-没有额外的查询。

经过更多的调查(事实上更多),我发现问题是这样的:

如果第一个MoveNext没有返回记录,则存在问题。查询是什么类型并不重要。收藏中有多少条目并不重要。

如果更改将最后一个条目作为第一个结果返回的查询,则一切正常。你可以丢弃这个,因为你已经知道了...

上面的示例之所以成功,是因为您最初获得的是集合中已经存在的所有记录。

羊舌兴文
2023-03-14

看来我找到了解决问题的办法!!

上述代码中的问题与查询有关:

Query.EQ("PROCESSED", false)

当我删除它并用基于文档id的查询替换它时,内存消耗问题消失了。进一步考虑一下,这个“已处理”属性在查询中并不是游标所必需的。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;
    }
}
 类似资料:
  • 我正在使用Scala、Akka和ReactiveMongo的Play框架。我想使用MongoDB中的集合作为循环队列。几个参与者可以在其中插入文件;一个参与者在这些文档可用时立即检索它们(一种发布-订阅系统)。我使用的是封顶系列和可裁剪光标。我总是用flush命令从同一个集合中检索所有元素,否则我就不可能用flush命令从该集合中检索所有元素。有没有替代方案?例如,有没有一种方法可以在不移除元素的

  • 我有50多个需要裁剪的光栅文件(ASCII格式)。我已经以ASCII格式从ArcMap导出了遮罩,并将其加载到R中。如何使其适用于一行中的所有光栅,并以与之前相同的名称导出它们(当然是在不同的文件夹中,以避免覆盖)? 我知道光栅软件包中有裁剪功能,但到目前为止我从未使用过。我只是把它们堆放起来做进一步的栖息地分析。 到目前为止,我的代码:

  • 我想从MongoDB集合中获取最后5个文档,然后继续跟踪它以获取新文档。这可以通过一个查询完成,还是我真的需要两个查询?如果有两个查询,在不添加额外字段的情况下实现这一点的最佳方法是什么? 虽然任何语言的答案都可以,但下面是一个示例节点。我试图实现的js代码片段(省略错误处理,并根据问题的第一个答案编辑代码片段): 问题:上面的代码从第一个文档开始打印所有文档,然后等待更多文档。选项和无效。 问题

  • 我整理了一些代码来从图像中提取所有字符。我从左到右对字符进行排序,并尝试将每个字符裁剪到单独的图像中。并非所有字符都被正确裁剪,其中一些最终大小为零。

  • 问题内容: 我正在尝试裁剪图像,然后将裁剪后的图像粘贴到另一个图像的中心。理想情况下,我希望裁切后的图像小于粘贴的图像,以便在粘贴的图像周围有一个边框,但我不知道这样是否可行。 这是我尝试过的方法(以及由此产生的错误消息): 我可以看到“区域”的大小已设为(0,0),但我不明白为什么。 任何对此的帮助将非常感谢 问题答案: 裁剪方法的PIL文档指出: 返回当前图像的矩形区域。该框是一个四元组,定义

  • 我试图在从图库中选择图像后使用intent来裁剪图像。以下是我的代码片段 在这里,我使用PICK_IMAGE_REQUEST意图句柄调用上面的代码段 由于我在裁剪后使用了相同的意图,即PICK_IMAGE_REQUEST,可能会出现什么问题