51

He estado jugando con MongoDB recientemente (Es INCREÍBLEMENTE RÁPIDO) usando el controlador C# en GitHub. Todo está funcionando bien en mi pequeña aplicación de consola única con la que estoy probando. Puedo agregar 1,000,000 de documentos (sí, millones) en menos de 8 segundos con un solo subproceso. Solo obtengo este rendimiento si uso la conexión fuera del alcance de un ciclo for. En otras palabras, mantengo la conexión abierta para cada inserción en lugar de conectarla para cada inserción. Obviamente eso es artificial..NET mejores prácticas para conexiones MongoDB?

Pensé en subirlo un poco para ver cómo funciona con múltiples hilos. Estoy haciendo esto porque necesito simular un sitio web con múltiples solicitudes simultáneas. Estoy girando entre 15 y 50 hilos, insertando un total de 150,000 documentos en todos los casos. Si solo dejo que los subprocesos se ejecuten, cada uno creando una nueva conexión para cada operación de inserción, el rendimiento se detiene.

Obviamente necesito encontrar una manera de compartir, bloquear o poner en común la conexión. Ahí radica la pregunta. ¿Cuál es la mejor práctica en términos de conexión a MongoDB? ¿Debería mantenerse la conexión abierta durante la vida de la aplicación (hay una latencia sustancial abriendo y cerrando la conexión TCP para cada operación)?

¿Alguien tiene experiencia en el mundo real o en la producción con MongoDB, y específicamente la conexión subyacente?

Aquí está mi muestra de subprocesamiento utilizando una conexión estática que está bloqueada para operaciones de inserción. ¡Ofrezca sugerencias que maximicen el rendimiento y la confiabilidad en un contexto 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); 
     } 
    } 
} 
+2

¿Qué decidieron al final? Enfrentando el mismo problema ... –

+4

La buena noticia es que no tuve que decidir. Los controladores Mongodb-csharp y NoRM agregaron soporte para la agrupación de conexiones. Ambas bibliotecas tienen mecanismos bien diseñados y seguros para las conexiones de agrupamiento contra un proceso mongod o mongos. Ambas áreas también agregan compatibilidad con conjuntos de réplicas en el futuro cercano. –

+0

@TylerBrinks ¿puede mostrar un ejemplo de cómo puede insertar documentos de 1 m en 8sec? No puedo alcanzar esa velocidad en un solo hilo. – IamStalker

Respuesta

9

Lo que hay que recordar acerca de una conexión estática es que se comparte entre todos sus hilos. Lo que quieres es una conexión por hilo.

+0

Es posible que se haya perdido la parte en la que afirmé que una conexión por hilo es notablemente lenta.No creo que esa sea la mejor respuesta para un sitio web de alto tráfico. –

+5

Para su muestra, donde está agrupando cosas, una por hilo es lo mejor que puede hacer. Una conexión estática y compartida _ generará bloqueos como los que está viendo. Su alternativa es hacer la agrupación de conexiones. Eso es algo que el proveedor de servidores sql tiene incorporado, pero para mongo tendrás que construir tú mismo, y no es trivial acertar. –

+1

Al ver esto de nuevo hoy, también es posible que tenga demasiados hilos. Idealmente, desea una cola compartida, segura para subprocesos para sus elementos de trabajo, y solo un puñado de subprocesos (el número exacto varía según su sistema, pero el factor más importante es la cantidad de núcleos de procesador). Cada hilo extrae elementos de la cola. Esto reduciría el número de conexiones, por lo que ya no son el cuello de botella. –

0

Connection Pool debería ser tu respuesta.

La función está en desarrollo (consulte http://jira.mongodb.org/browse/CSHARP-9 para obtener más información).

En este momento, para aplicaciones web, la mejor práctica es conectarse en BeginRequest y liberar la conexión en EndRequest. Pero para mí, creo que la operación es demasiado costosa para cada solicitud sin Connection Pool. Así que decido tener el objeto Mongo global y usarlo como recurso compartido para cada subproceso (si obtiene el último controlador C# de github en este momento, también mejora un poco el rendimiento para la concurrencia).

No conozco la desventaja de utilizar el objeto Global Mongo. Así que esperemos a que otro experto lo comente.

Pero creo que puedo vivir con él hasta que se haya completado la característica (conjunto de conexiones).

+0

¿Utiliza de la misma manera con la conexión a SQL Server/MySQL? Creo que las mejores prácticas con la agrupación de conexiones todavía son "abrir tarde, cerrar temprano", y casi no cuesta nada abrir/cerrar una conexión muchas veces durante una solicitud. –

1

Un poco pero todavía de interés es CSMongo, un controlador C# para MongoDB creado por el desarrollador de jLinq. Aquí hay un ejemplo:

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

} 
6

Al usar mongodb-csharp, lo trata como si fuera una conexión ADO. Cuando crea un objeto Mongo toma prestada una conexión del grupo, que posee hasta que se elimina. Entonces, después del bloque de uso, la conexión vuelve al grupo. La creación de objetos Mongo es barata y rápida.

Ejemplo

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

base de datos de registro de
Mie Jun 02 20:54:21 conexión aceptado de 127.0.0.1:58214 # 1
Mie Jun 02 20:54:21 conexión aceptado de 127.0.0.1:58215 # 2
Mié Jun 02 20:54:21 MessagingPort recv() errno: 0 Ningún error 127.0.0.1:58214
Mié Jun 02 20:54:21 conexión final 127.0.0.1:58214
Wed Jun 02 20:54:21 MessagingPort recv() Error: 0 Sin errores 127.0.0.1:58215
Wed Jun 02 20:54:21 extremo de conexión 127.0.0.1:58215

Aviso sólo abrió 2 conexiones.

Puse esto junto usando el foro mongodb-csharp. http://groups.google.com/group/mongodb-csharp/browse_thread/thread/867fa78d726b1d4

+1

La mejor respuesta hasta ahora. ¡Gracias! :) –

0

estoy usando conductor CSharp-mongodb y no me ayuda con su grupo de conexión :(Tengo alrededor de 10-20 solicitud a MongoDB por solicitud Web (150 usuarios en línea - promedio). Y puedo' ni siquiera supervisar las estadísticas o conectarse a MongoDB de concha que excepción tiro me

he creado repositorio, que se abren y disponer de conexión por la petición que se basan en cosas tales como:.. 1) el conductor tiene la agrupación de conexiones 2) Después de mi investigación (he publicado alguna pregunta en grupos de usuarios sobre esto), entendí que la creación de objetos mongo y la conexión abierta no requiere un funcionamiento pesado, por lo que el funcionamiento es muy intenso.

Pero hoy mi producción descienden :( Puede ser que tengo que guardar conexión abierta por la petición ...

aquí es un enlace a un grupo de usuarios http://groups.google.com/group/mongodb-user/browse_thread/thread/3d4a4e6c5eb48be3#

54

La mayoría de respuestas aquí son obsoletas y son ya no es aplicable características innumerables como el conductor .net ha madurado y se había añadido

en cuanto a la documentación del nuevo controlador 2.0 se encuentra aquí:. http://mongodb.github.io/mongo-csharp-driver/2.0/reference/driver/connecting/

El controlador .net ahora es seguro para subprocesos y maneja la agrupación de conexiones. De acuerdo con la documentación

Se recomienda almacenar una instancia MongoClient en un lugar global, ya sea como una variable estática o en un contenedor IoC con una vida útil única.

+0

Esta respuesta debe enviarse a la parte superior. ¡Toma mi voto! – Zignd

Cuestiones relacionadas