71

我最近一直在使用 GitHub 上的 C# 驱动程序玩 MongoDB(速度非常快)。在我正在测试的小型单线程控制台应用程序中,一切正常。我能够在运行单线程的 8 秒内添加 1,000,000 个文档(是的,百万个)。如果我在 for 循环范围之外使用连接,我只会获得这种性能。换句话说,我为每个插入保持连接打开,而不是为每个插入连接。显然这是人为的。

我想我会把它提高一个档次,看看它是如何与多线程一起工作的。我这样做是因为我需要模拟一个具有多个并发请求的网站。我在 15 到 50 个线程之间旋转,在所有情况下仍然插入总共 150,000 个文档。如果我只是让线程运行,每个线程为每个插入操作创建一个新连接,性能就会停止。

显然,我需要找到一种方法来共享、锁定或池化连接。问题就在于此。连接到 MongoDB 的最佳实践是什么?连接是否应该在应用程序的整个生命周期内保持打开状态(每次操作打开和关闭 TCP 连接都有相当长的延迟)?

是否有人对 MongoDB 有任何实际或生产经验,特别是底层连接?

这是我使用为插入操作锁定的静态连接的线程示例。请提供可以在网络环境中最大化性能和可靠性的建议!

private static Mongo _mongo;

private static void RunMongoThreaded()
{
    _mongo = new Mongo();
    _mongo.Connect();

    var threadFinishEvents = new List<EventWaitHandle>();

    for(var i = 0; i < 50; i++)
    {
        var threadFinish = new EventWaitHandle(false, EventResetMode.ManualReset);
        threadFinishEvents.Add(threadFinish);

        var thread = new Thread(delegate()
            {
                 RunMongoThread();
                 threadFinish.Set();
            });

        thread.Start();
    }

    WaitHandle.WaitAll(threadFinishEvents.ToArray());
    _mongo.Disconnect();
}

private static void RunMongoThread()
{
    for (var i = 0; i < 3000; i++)
    {
        var db = _mongo.getDB("Sample");
        var collection = db.GetCollection("Users");
        var user = GetUser(i);
        var document = new Document();
        document["FirstName"] = user.FirstName;
        document["LastName"] = user.LastName;

        lock (_mongo) // Lock the connection - not ideal for threading, but safe and seemingly fast
        {
            collection.Insert(document);
        }
    }
}
4

6 回答 6

136

这里的大多数答案都已过时并且不再适用,因为 .net 驱动程序已经成熟并添加了无数功能。

查看此处找到的新 2.0 驱动程序的文档:http: //mongodb.github.io/mongo-csharp-driver/2.0/reference/driver/connecting/

.net 驱动程序现在是线程安全的并处理连接池。根据文档

建议将 MongoClient 实例存储在全局位置,作为静态变量或在具有单例生命周期的 IoC 容器中。

于 2015-06-12T18:49:32.700 回答
9

关于静态连接要记住的一点是它在所有线程之间共享。您想要的是每个线程一个连接。

于 2010-02-03T17:47:18.277 回答
6

使用 mongodb-csharp 时,您会像对待 ADO 连接一样对待它。当你创建一个 Mongo 对象时,它会从池中借用一个连接,直到它被释放为止。因此,在 using 块之后,连接又回到了池中。创建 Mongo 对象既便宜又快速。

例子

for(var i=0;i<100;i++) 
{ 
        using(var mongo1 = new Mongo()) 
        using(var mongo2 = new Mongo()) 
        { 
                mongo1.Connect(); 
                mongo2.Connect(); 
        } 
} 

数据库日志6 月 2 日星期三
20:54:21 从 127.0.0.1:58214 #1 接受了
连接 6 月 02 日星期三 20:54:21 从 127.0.0.1:58215 #2 接受了连接 6月 2 日
星期三 20:54:21 MessagingPort recv() errno:0 没有错误 127.0.0.1:58214
6 月 2 日星期三 20:54:21 结束连接 127.0.0.1:58214
6 月 2 日星期三 20:54:21 MessagingPort recv() errno:0 没有错误 127.0.0.1:58215
6 月 2 日星期三20:54:21 结束连接 127.0.0.1:58215

请注意,它只打开了 2 个连接。

我使用 mongodb-csharp 论坛把它放在一起。 http://groups.google.com/group/mongodb-csharp/browse_thread/thread/867fa78d726b1d4

于 2010-11-05T15:54:00.933 回答
1

有点但仍然令人感兴趣的是CSMongo,它是由 jLinq 的开发人员创建的 MongoDB 的 C# 驱动程序。这是一个示例:

//create a database instance
using (MongoDatabase database = new MongoDatabase(connectionString)) {

    //create a new document to add
    MongoDocument document = new MongoDocument(new {
        name = "Hugo",
        age = 30,
        admin = false
    });

    //create entire objects with anonymous types
    document += new {
        admin = true,
        website = "http://www.hugoware.net",
        settings = new {
            color = "orange",
            highlight = "yellow",
            background = "abstract.jpg"
        }
    };

    //remove fields entirely
    document -= "languages";
    document -= new[] { "website", "settings.highlight" };

    //or even attach other documents
    MongoDocument stuff = new MongoDocument(new {
        computers = new [] { 
            "Dell XPS", 
            "Sony VAIO", 
            "Macbook Pro" 
            }
        });
    document += stuff;

    //insert the document immediately
    database.Insert("users", document);

}
于 2010-03-07T12:34:10.660 回答
0

我正在使用 csharp-mongodb 驱动程序,但它对他的连接池没有帮助:(每个 Web 请求我大约有 10-20 个对 mongodb 的请求。(150 个在线用户 - 平均)而且我什至无法监控统计数据或连接从 shell 到 mongodb 它会向我抛出异常。

我创建了存储库,它根据请求打开和处理连接。我依赖这样的东西:1)驱动程序有连接池2)经过我的研究(我已经在用户组中发布了一些关于这个的问题) - 我明白创建mongo对象和打开连接不会繁重的操作,所以繁重的操作。

但是今天我的产量下降了:(也许我必须为每个请求保存打开的连接......

这是用户组的链接http://groups.google.com/group/mongodb-user/browse_thread/thread/3d4a4e6c5eb48be3#

于 2010-12-08T21:12:15.570 回答
0

连接池应该是您的答案。

该功能正在开发中(有关详细信息,请参阅http://jira.mongodb.org/browse/CSHARP-9 )。

目前,对于 Web 应用程序,最佳实践是在 BeginRequest 处连接并在 EndRequest 处释放连接。但是对我来说,我认为对于没有连接池的每个请求来说,操作成本太高了。因此,我决定拥有全局 Mongo 对象并将其用作每个线程的共享资源(如果您现在从 github 获得最新的 C# 驱动程序,它们还会稍微提高并发性能)。

我不知道使用 Global Mongo 对象的缺点。所以让我们等待另一位专家对此发表评论。

但我认为我可以忍受它,直到功能(连接池)完成。

于 2010-03-07T12:23:45.940 回答