51

Recentemente ho suonato con MongoDB (È FANTASTICAMENTE VELOCE) usando il driver C# su GitHub. Tutto funziona perfettamente nella mia piccola app per console a thread singolo con cui sto testando. Sono in grado di aggiungere 1.000.000 di documenti (sì, milioni) in meno di 8 secondi con un singolo thread. Ottengo questa prestazione solo se utilizzo la connessione al di fuori dell'ambito di un ciclo for. In altre parole, sto mantenendo la connessione aperta per ogni inserto piuttosto che la connessione per ogni inserto. Ovviamente è forzato.Migliori pratiche .NET per le connessioni MongoDB?

Ho pensato di fare un salto di una tacca per vedere come funziona con più thread. Lo sto facendo perché ho bisogno di simulare un sito Web con più richieste simultanee. Sto girando tra i 15 e i 50 thread, inserendo ancora un totale di 150.000 documenti in tutti i casi. Se faccio solo girare i thread, creando ciascuno una nuova connessione per ogni operazione di inserimento, le prestazioni si arrestano.

Ovviamente ho bisogno di trovare un modo per condividere, bloccare o mettere in comune la connessione. Qui sta la domanda. Qual è la migliore pratica in termini di connessione a MongoDB? La connessione deve essere mantenuta aperta per tutta la durata dell'app (c'è una latenza sostanziale che apre e chiude la connessione TCP per ogni operazione)?

Qualcuno ha un'esperienza di produzione o di mondo reale con MongoDB, e in particolare la connessione sottostante?

Ecco il mio esempio di threading utilizzando una connessione statica bloccata per operazioni di inserimento. Si prega di offrire suggerimenti che ottimizzino le prestazioni e l'affidabilità in un contesto 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

Cosa hai deciso alla fine? Di fronte allo stesso problema ... –

+4

La buona notizia è che non dovevo decidere. I driver Mongodb-csharp e NoRM hanno entrambi aggiunto il supporto per il pool di connessioni. Entrambe le librerie dispongono di meccanismi ben progettati e thread-safe per mettere in comune le connessioni con un processo mongod o mongos. Entrambe le aree aggiungono anche il supporto per i set di repliche nel prossimo futuro. –

+0

@TylerBrinks puoi mostrare un esempio di come puoi inserire documenti da 1m sotto 8 sec? Non riesco a raggiungere quella velocità, su un singolo thread. – IamStalker

risposta

9

La cosa da ricordare su una connessione statica è che è condivisa tra tutti i thread. Quello che vuoi è una connessione per thread.

+0

Potrebbe essersi persa la parte in cui ho affermato che una connessione per thread è notevolmente lenta.Non penso che sia la migliore risposta per un sito web ad alto traffico. –

+5

Per il tuo campione, dove stai raggruppando le cose, uno per thread è il meglio che puoi fare. Una connessione statica e condivisa creerà deadlock come stai vedendo. La tua alternativa è fare il pool di connessioni. Questo è qualcosa che il provider di SQL Server ha incorporato ma per mongo dovrai costruirti da solo, e non è banale ragionare. –

+1

Guardando ancora oggi, è anche possibile che tu abbia troppi thread. Idealmente, si desidera una coda condivisa e sicura per i thread per gli elementi di lavoro e solo una manciata di thread (il numero esatto varia a seconda del sistema, ma il fattore più importante è il numero di core del processore). Ogni thread estrae gli elementi dalla coda. Ciò ridurrebbe il numero di connessioni in modo che non fossero più il collo di bottiglia. –

0

Connection Pool dovrebbe essere la vostra risposta.

La funzione è in fase di sviluppo (vedere http://jira.mongodb.org/browse/CSHARP-9 per ulteriori dettagli).

Al momento, per l'applicazione Web, la procedura consigliata è connettersi a BeginRequest e rilasciare la connessione su EndRequest. Ma per me, penso che l'operazione sia troppo costosa per ogni richiesta senza Connection Pool. Così decido di avere l'oggetto Mongo globale e di usarlo come risorsa condivisa per ogni thread (se ora ottieni l'ultimo driver C# da github, migliorano anche le prestazioni per la concorrenza).

Non conosco lo svantaggio per l'utilizzo dell'oggetto Global Mongo. Quindi aspettiamo un altro esperto per commentare questo.

Ma penso di poter convivere fino a quando la funzione (Pool di connessioni) non è stata completata.

+0

Si utilizza allo stesso modo con la connessione a SQL Server/MySQL? Penso che le migliori pratiche con il pooling delle connessioni siano ancora "aperte in ritardo, chiudono presto" e quasi non costa nulla aprire/chiudere una connessione molte volte durante una richiesta. –

1

Un po 'ma ancora di interesse è CSMongo, un driver C# per MongoDB creato dallo sviluppatore di jLinq. Ecco un esempio:

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

Quando si utilizza mongodb-csharp lo si tratta come se fosse una connessione ADO. Quando si crea un oggetto Mongo prende in prestito una connessione dal pool, che possiede finché non viene eliminata. Quindi, dopo l'utilizzo del blocco, la connessione ritorna nel pool. Creare oggetti Mongo è economico e veloce.

Esempio

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

Database Log
mer 2 giugno 20:54:21 connessione accettato dal 127.0.0.1:58214 # 1
mer 2 giugno 20:54:21 collegamento accettato da 127.0.0.1:58215 # 2
Wed Jun 02 20:54:21 MessagingPort recv() errno: 0 Nessun errore 127.0.0.1:58214
Wed Jun 02 20:54:21 connessione finale 127.0.0.1:58214
Mer 2 giugno 20:54:21 MessagingPort recv() errno: 0 Nessun errore 127.0.0.1:58215
mer 2 giugno 20:54:21 fine connessione 127.0.0.1:58215

Avviso solo aperto 2 connessioni.

L'ho messo insieme usando il forum mongodb-csharp. http://groups.google.com/group/mongodb-csharp/browse_thread/thread/867fa78d726b1d4

+1

La migliore risposta finora. Grazie! :) –

0

Sto usando il driver csharp-MongoDB e non mi aiuta con il suo pool di connessioni :(ho circa 10-20 richiesta di MongoDB per ogni richiesta web (150 utenti in linea - media). E posso' t anche monitorare le statistiche o connettersi a MongoDB da shell si fa eccezione tiro a me

ho creato repository, che si aprono e disporre di connessione per ogni richiesta mi baso su cose come:.. 1) il driver ha pool di connessioni 2) Dopo la mia ricerca (ho postato qualche domanda in gruppi di utenti su questo) - ho capito che creare l'oggetto mongo e aprire la connessione non è un'operazione pesante, un'operazione così pesante.

Ma oggi la mia produzione va giù :( Può essere devo salvare connessione aperta per richiesta ...

qui è link per gruppo di utenti http://groups.google.com/group/mongodb-user/browse_thread/thread/3d4a4e6c5eb48be3#

54

La maggior parte delle risposte qui sono obsoleti e sono non sono più applicabili le caratteristiche innumerevoli come il conducente .net è maturato e aveva aggiunto

Guardando la documentazione del nuovo driver 2.0 trovato qui:. http://mongodb.github.io/mongo-csharp-driver/2.0/reference/driver/connecting/

Il driver .net ora è thread-safe e gestisce il pool di connessioni. In base alla documentazione

Si consiglia di archiviare un'istanza MongoClient in un luogo globale, come variabile statica o in un contenitore IoC con una durata del singleton.

+0

Questa risposta deve essere inviata in alto. Prendi il mio upvote! – Zignd

Problemi correlati