.NET лучшие практики для соединений MongoDB?
Недавно я играл с MongoDB (это удивительно FAST), используя драйвер С# на GitHub. Все работает отлично в моем маленьком однопоточном консольном приложении, с которым я тестирую. Я могу добавить 1 000 000 документов (да, миллион) за менее чем 8 секунд, используя одну цепочку. Я получаю эту производительность только в том случае, если я использую соединение за пределами цикла 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);
}
}
}
Ответы
Ответ 1
Большинство ответов здесь устарели и больше не применимы, поскольку драйвер .net созрел и добавил бесчисленные функции.
Глядя на документацию о новом драйвере 2.0, найденном здесь:
http://mongodb.github.io/mongo-csharp-driver/2.0/reference/driver/connecting/
Драйвер .net теперь потокобезопасен и обрабатывает пул соединений. Согласно документации
Рекомендуется хранить экземпляр MongoClient в глобальном месте либо в виде статической переменной, либо в контейнере IoC с одним временем жизни.
Ответ 2
Вещь, которую следует помнить о статическом соединении, заключается в том, что она разделялась между всеми вашими потоками. То, что вы хотите, - это одно соединение на поток.
Ответ 3
При использовании 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();
}
}
Журнал базы данных
Ср Июн 02 20:54:21 Связь принята с 127.0.0.1:58214 # 1
Ср Июн 02 20:54:21 Связь принята с 127.0.0.1:58215 # 2
Wed Jun 02 20:54:21 MessagingPort recv() errno: 0 Нет ошибки 127.0.0.1:58214
Wed Jun 02 20:54:21 end connection 127.0.0.1:58214
Wed Jun 02 20:54:21 MessagingPort recv() errno: 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
Ответ 4
Немного, но все же интересный CSMongo, - драйвер С# для MongoDB, созданный разработчиком jLinq. Здесь образец:
//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);
}
Ответ 5
Пул соединений должен быть вашим ответом.
Эта функция разрабатывается (подробнее см. http://jira.mongodb.org/browse/CSHARP-9).
В настоящее время для веб-приложения лучше всего подключиться к BeginRequest и освободить соединение в EndRequest. Но для меня, я думаю, что операция слишком дорога для каждого запроса без пула соединений. Поэтому я решил иметь глобальный объект Mongo и использовать его как общий ресурс для каждого потока (если вы получаете последний драйвер С# из github прямо сейчас, они также немного улучшают производительность для concurrency).
Я не знаю недостатка в использовании объекта Global Mongo. Поэтому позвольте подождать еще одного эксперта, чтобы прокомментировать это.
Но я думаю, что смогу жить с ним до тех пор, пока функция (Пул соединений) не будет завершена.
Ответ 6
Я использую драйвер csharp-mongodb, и это не помогает мне с его пулом подключений:( У меня около 10-20 запросов к mongodb на веб-запрос. (150 пользователей онлайн - средний) И я даже не могу контролировать статистика или подключиться к mongodb из оболочки, это исключение для меня.
Я создал репозиторий, который открывает и удаляет соединение для каждого запроса. Я полагаюсь на такие вещи, как:
1) У драйвера есть пул соединений
2) После моего исследования (я разместил в группах пользователей некоторый вопрос об этом) - я понял, что создание объекта mongo и открытого соединения не требует большой нагрузки, поэтому тяжелая операция.
Но сегодня мое производство идет вниз:(
Может быть, мне нужно сохранить открытое соединение для каждого запроса...
здесь ссылка на группу пользователей http://groups.google.com/group/mongodb-user/browse_thread/thread/3d4a4e6c5eb48be3#