【问题标题】:MongoDB 2.4.8 capped collection and tailable cursor consuming all memoryMongoDB 2.4.8 限制集合和可尾游标消耗所有内存
【发布时间】:2014-01-09 02:40:29
【问题描述】:

我们目前正在探索 MongoDB 中的 Capped Collections 和 Tailable Cursors,以创建一个用于通知的排队系统。然而,在创建了一个简单的 LinqPad 测试(下面的代码)之后,我们注意到在运行时,即使我们没有插入任何记录,Mongo 也会不断地分配内存,直到没有更多可用资源。这种分配一直​​持续到所有系统 RAM 都用完,此时 Mongo 会停止响应。

由于我们是 Capped Collections 和 Tailable Cursors 的新手,我想确保在提交错误之前我们没有遗漏一些明显的东西。

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

  • 平台:Windows Server 2012 64bit
  • 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;
    }
}

【问题讨论】:

  • 你能运行 db.currentOp() 吗?您还可以发布涵盖运行的 mongod 日志文件吗?
  • 我遇到了同样的问题...看来,mongoDB 在运行时将整个 oplog 保存在 RAM 中。对于信息,我使用单台机器,仅为此功能添加复制。这是我的当前操作和日志:dl.dropboxusercontent.com/u/853035/currentOp.txtdl.dropboxusercontent.com/u/853035/log.txt
  • 现在我发现第一次进入MoveNext时内存使用量约为2.4GB。返回第一个文档后,它下降到 1.2GB,第二个文档后它又回到了原始值???看这里的图片:dl.dropboxusercontent.com/u/853035/memory_usage.png
  • @Needleski,当你说“MongoDB”消耗所有内存时,你指的是服务器还是驱动程序?
  • @CraigWilson 服务器进程(Windows 上的 mongod.exe)

标签: c# windows mongodb capped-collections


【解决方案1】:

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

上述代码中的问题围绕查询:

Query.EQ("PROCESSED", false)

当我删除它并用基于文档 id 的查询替换它时,内存消耗问题就消失了。进一步思考,查询中确实不需要此“已处理”属性,因为 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;
    }
}

【讨论】:

    【解决方案2】:

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

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

    如果第一个 MoveNext 没有返回记录,则存在问题。 查询的类型无关紧要。 集合中有多少条目并不重要。

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

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

    【讨论】:

      猜你喜欢
      • 2012-08-18
      • 2015-07-30
      • 2020-08-10
      • 2011-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-30
      • 1970-01-01
      相关资源
      最近更新 更多