我最近一直在使用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);
}
}
}
答案 0 :(得分:88)
此处的大部分答案都已过时,因为.net驱动程序已经成熟并添加了无数功能,因此不再适用。
查看此处的新2.0驱动程序的文档: http://mongodb.github.io/mongo-csharp-driver/2.0/reference/driver/connecting/
.net驱动程序现在是线程安全的并处理连接池。根据文件
建议将MongoClient实例存储在全局位置,可以是静态变量,也可以是具有单例生存期的IoC容器。
答案 1 :(得分:9)
要记住静态连接的事情是它在所有线程之间共享。你想要的是每个线程一个连接。
答案 2 :(得分:5)
使用mongodb-csharp时,您会像处理ADO连接一样对待它。 当你创建一个Mongo对象时,它借用了池所拥有的连接,直到它被处置为止。因此,在使用块之后,连接将重新进入池中。 创建Mongo对象既便宜又快捷。
示例强>
for(var i=0;i<100;i++)
{
using(var mongo1 = new Mongo())
using(var mongo2 = new Mongo())
{
mongo1.Connect();
mongo2.Connect();
}
}
数据库日志
Wed Jun 02 20:54:21从127.0.0.1:58214接受连接#1
2月2日星期三20:54:21从127.0.0.1:58215接受连接#2
Wed Jun 02 20:54:21 MessagingPort recv()errno:0无错误127.0.0.1:58214
2月2日星期三20:54:21结束连接127.0.0.1:58214
Wed Jun 02 20:54:21 MessagingPort recv()错误号:0无错误127.0.0.1:58215
Wed Jun 02 20:54:21 end connection 127.0.0.1:58215
注意它只打开了2个连接。
我使用mongodb-csharp论坛把它放在一起。 http://groups.google.com/group/mongodb-csharp/browse_thread/thread/867fa78d726b1d4
答案 3 :(得分:1)
对于由jLinq的开发者创建的MongoDB的CSMongo, 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);
}
答案 4 :(得分:0)
连接池应该是你的答案。
正在开发此功能(有关详情,请参阅http://jira.mongodb.org/browse/CSHARP-9)。
目前,对于Web应用程序,最佳做法是在BeginRequest上连接并在EndRequest上释放连接。但对我来说,我认为对于没有连接池的每个请求,操作太昂贵了。所以我决定使用全局Mongo对象并将其用作每个线程的共享资源(如果你现在从github获得最新的C#驱动程序,它们也会提高并发性能)。
我不知道使用Global Mongo对象的缺点。所以让我们等待另一位专家对此发表评论。
但我认为我可以忍受它,直到功能(连接池)完成。
答案 5 :(得分:0)
我正在使用csharp-mongodb驱动程序,它对我的连接池没有帮助:(我有大约10-20请求mongodb每个网页请求。(150个用户在线 - 平均)我甚至无法监控统计或从shell连接到mongodb它会向我抛出异常。
我创建了存储库,每个请求都打开并处理连接。我依靠这样的事情: 1)驱动程序有连接池 2)经过我的研究(我已经在用户组中发布了一些关于此的问题) - 我明白创建mongo对象和打开连接不会操作繁重,操作繁重。
但今天我的作品下降了:( 可能是我必须保存每个请求的开放连接...
此处是指向用户组http://groups.google.com/group/mongodb-user/browse_thread/thread/3d4a4e6c5eb48be3#
的链接