web-dev-qa-db-fra.com

Meilleures pratiques .NET pour les connexions MongoDB?

J'ai joué avec MongoDB récemment (c'est incroyablement rapide) en utilisant le pilote C # sur GitHub. Tout fonctionne très bien dans ma petite application de console à thread unique avec laquelle je teste. Je peux ajouter 1 000 000 de documents (oui, des millions) en moins de 8 secondes avec un seul thread. Je n'obtiens cette performance que si j'utilise la connexion en dehors de la portée d'une boucle for. En d'autres termes, je garde la connexion ouverte pour chaque insert plutôt que de me connecter pour chaque insert. De toute évidence, c'est artificiel.

Je pensais que je le monterais d'un cran pour voir comment cela fonctionne avec plusieurs threads. Je fais cela parce que je dois simuler un site Web avec plusieurs demandes simultanées. Je tourne entre 15 et 50 fils, insérant toujours un total de 150 000 documents dans tous les cas. Si je laisse les threads s'exécuter, chacun créant une nouvelle connexion pour chaque opération d'insertion, les performances s'arrêtent.

Évidemment, je dois trouver un moyen de partager, verrouiller ou mettre en commun la connexion. C'est là que réside la question. Quelle est la meilleure pratique en termes de connexion à MongoDB? La connexion doit-elle rester ouverte pendant toute la durée de vie de l'application (il y a une latence importante ouvrant et fermant la connexion TCP pour chaque opération)?

Quelqu'un a-t-il une expérience du monde réel ou de la production avec MongoDB, et en particulier la connexion sous-jacente?

Voici mon exemple de filetage utilisant une connexion statique verrouillée pour les opérations d'insertion. Veuillez proposer des suggestions qui maximiseraient les performances et la fiabilité dans un contexte Web!

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);
        }
    }
}
63
Tyler Brinks

La plupart des réponses ici sont obsolètes et ne sont plus applicables car le pilote .net est arrivé à maturité et a ajouté de nombreuses fonctionnalités.

En regardant la documentation du nouveau pilote 2.0 trouvé ici: http://mongodb.github.io/mongo-csharp-driver/2.0/reference/driver/connecting/

Le pilote .net est désormais thread-safe et gère le pool de connexions. Selon la documentation

Il est recommandé de stocker une instance MongoClient dans un emplacement global, soit en tant que variable statique, soit dans un conteneur IoC avec une durée de vie singleton.

95

La chose à retenir sur une connexion statique est qu'elle est partagée entre tous vos threads. Ce que vous voulez, c'est une connexion par thread.

9
Joel Coehoorn

Lorsque vous utilisez mongodb-csharp, vous le traitez comme vous le feriez avec une connexion ADO. Lorsque vous créez un objet Mongo, il emprunte une connexion au pool, qu'il possède jusqu'à ce qu'il soit supprimé. Donc, après l'utilisation de bloquer la connexion est de retour dans le pool. La création d'objets Mongo est bon marché et rapide.

Exemple

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

Journal de la base de données
mer. Juin 02 20:54:21 connexion acceptée à partir du 127.0.0.1:58214 # 1
Mer. Juin 02 20:54:21 connexion acceptée à partir du 127.0.0.1:58215 # 2
Mer. Juin 02 20:54:21 MessagingPort recv () errno: 0 Aucune erreur 127.0.0.1:58214
Mer. Juin 02 20:54:21 fin de connexion 127.0.0.1:58214
Mer. Juin 02 20:54:21 MessagingPort recv () errno: 0 Aucune erreur 127.0.0.1:58215
Mer. Juin 02 20:54:21 fin de connexion 127.0.0.1:58215

Notez qu'il n'a ouvert que 2 connexions.

J'ai mis cela ensemble en utilisant le forum mongodb-csharp. http://groups.google.com/group/mongodb-csharp/browse_thread/thread/867fa78d726b1d4

5
Donny V.

Un peu mais toujours intéressant est CSMongo, un pilote C # pour MongoDB créé par le développeur de jLinq. Voici un exemple:

//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);

}
1
David Robbins

Connection Pool devrait être votre réponse.

La fonctionnalité est en cours de développement (veuillez consulter http://jira.mongodb.org/browse/CSHARP-9 pour plus de détails).

À l'heure actuelle, pour les applications Web, la meilleure pratique consiste à se connecter à BeginRequest et à libérer la connexion à EndRequest. Mais pour moi, je pense que l'opération est trop chère pour chaque requête sans Connection Pool. Je décide donc d'avoir l'objet global Mongo et de l'utiliser comme ressource partagée pour tous les threads (si vous obtenez le dernier pilote C # de github en ce moment, ils améliorent également un peu les performances de la concurrence).

Je ne connais pas l'inconvénient d'utiliser l'objet Global Mongo. Attendons donc qu'un autre expert commente cela.

Mais je pense que je peux vivre avec jusqu'à ce que la fonctionnalité (pool de connexions) soit terminée.

0
ensecoz

J'utilise le pilote csharp-mongodb et cela ne m'aide pas avec son pool de connexions :( J'ai environ 10-20 demandes de mongodb par demande Web. (150 utilisateurs en ligne en moyenne) Et je ne peux même pas surveiller les statistiques ou me connecter pour mongodb de Shell, cela me fait exception.

J'ai créé un référentiel qui ouvre et supprime la connexion par demande. Je m'appuie sur des choses telles que: 1) Le pilote a un pool de connexions 2) Après mes recherches (j'ai posté une question dans les groupes d'utilisateurs à ce sujet) - j'ai compris que créer un objet mongo et une connexion ouverte ne fonctionne pas lourdement, donc une opération lourde.

Mais aujourd'hui, ma production baisse :( Peut-être que je dois enregistrer la connexion ouverte par demande ...

voici le lien vers le groupe d'utilisateurs http://groups.google.com/group/mongodb-user/browse_thread/thread/3d4a4e6c5eb48be3#

0
Antony Blazer