2015-07-22 8 views
5

Sto lavorando al backend del nodo cercando di ottimizzare una query molto pesante su mongodb via mangusta. Le dimensioni di ritorno previste sono considerevoli, ma per qualche motivo quando faccio la richiesta, il nodo inizia a consumare enormi quantità di memoria, ad esempio 200mb + per una singola grande richiesta.Modo per ridurre l'utilizzo della memoria da parte di mangusta quando si esegue la query

Considerando che la dimensione del reso è inferiore a 10 MB nella maggior parte dei casi, questo non sembra giusto. Rifiuta anche di lasciare andare la memoria dopo che è finita, so che probabilmente è solo il V8 GC a fare il suo comportamento predefinito, ma ciò che mi preoccupa è l'enorme quantità di memoria che viene consumata per una singola richiesta find().

L'ho isolato attraverso il test alla chiamata find(). Una volta eseguita la chiamata, esegue alcune operazioni di post-elaborazione, quindi invia i dati a un callback, il tutto in una funzione anonima. Ho provato a utilizzare il querystream al posto di model.find(), ma non mostra miglioramenti reali.

Guardarsi intorno non ha prodotto alcuna risposta, quindi chiederò, esiste un modo noto per ridurre, controllare o ottimizzare l'utilizzo della memoria da parte di mangusta? Qualcuno sa perché viene utilizzata così tanta memoria in eccesso per una singola chiamata?

EDIT

Secondo Johnny e Blakes suggerimenti, utilizzando miscela magra() con lo streaming, e utilizzando pausa e riprendere hanno migliorato l'utilizzo della memoria runtime e immensamente. Grazie!

+0

Quando si elabora l'output '.stream()', si chiama mai '.pause()'? O in effetti quali azioni stai eseguendo nel processore di eventi "dati" e ci sono altri strumenti di controllo delle code lì? –

+0

Non faccio nessuna pausa o riprendo le chiamate. Nei dati, tutto ciò che sto facendo è accodare i documenti su una matrice per essere inviati attraverso la richiamata alla chiusura. – Javeed

risposta

7

È possibile utilizzare l'opzione lean per una query Mongoose per tutto il tempo in cui sono necessari solo i documenti JavaScript normali e non le istanze di documento Mongoose completo. Ciò si traduce in prestazioni più veloci e ridotto utilizzo della memoria.

model.find().lean().exec(function(err, docs) {...}); 

È possibile anche combinare lean() con il flusso continuo dei risultati che dovrebbero ridurre ulteriormente l'utilizzo della memoria.

var stream = model.find().lean().stream(); 
+1

Ha funzionato come un incantesimo, grazie! – Javeed

+0

Grazie per questo suggerimento, approssimativamente, quanto di un miglioramento potrebbe portare? EDIT: ho effettivamente trovato questo: https://groups.google.com/forum/#!topic/mongoose-orm/u2_DzDydcnA/discussion Che indica circa 3 volte il miglioramento delle prestazioni di 3,5 volte –

6

mangusta predefinito .find() ovviamente restituisce tutti i risultati come un "allineamento", in modo che sta andando sempre di utilizzare la memoria con grandi risultati, quindi questo lascia l'interfaccia "stream".

Il problema di base qui è che si sta utilizzando un'interfaccia stream (poiché questa eredita dal flusso del nodo di base) ogni evento di dati "si attiva" e il gestore di eventi associato viene eseguito in modo continuo.

Ciò significa che anche con un "flusso" le azioni successive nel gestore eventi si "accumulano", per lo meno consumano molta memoria e possibilmente divorano lo stack di chiamate se ci sono ulteriori processi asincroni che vengono attivati ​​in Là.

Quindi la cosa migliore che puoi fare è iniziare a "limitare" le azioni nel tuo stream di elaborazione. Questo è semplice come chiamare il metodo .pause():

var stream = model.find().stream(); // however you call 

stream.on("data",function() { 
    // call pause on entry 
    stream.pause(); 

    // do processing 
    stream.resume();   // then resume when done 
}); 

Così .pause() ferma gli eventi nel flusso di essere emessi e questo permette le azioni nel vostro gestore di eventi per completare prima di continuare in modo che essi non sono tutti provenienti in una volta.

Quando il codice di gestione è completo, si chiama .resume(), direttamente all'interno del blocco come mostrato qui all'interno del blocco callback di qualsiasi azione asincrona eseguita all'interno del blocco.Notare che le stesse regole si applicano alle azioni asincrone e che "tutto" deve segnalare il completamento prima di chiamare il curriculum.

Ci sono altre ottimizzazioni che possono essere applicate, e si potrebbe fare bene a guardare i moduli disponibili di "elaborazione della coda" o "controllo del flusso asincrono" per aiutarvi a ottenere maggiori prestazioni con qualche esecuzione parallela di questo.

Ma in sostanza, pensare a .pause() quindi elaborare e .resume() continuare a evitare di consumare molta memoria durante l'elaborazione.

Inoltre, prestare attenzione alle "uscite" e, allo stesso modo, provare a utilizzare di nuovo uno "stream" se si crea qualcosa per una risposta. Tutto questo non servirà a niente se il lavoro che stai facendo sta semplicemente creando un'altra variabile in memoria, quindi aiuta a esserne consapevole.

+0

Queste e le risposte di JohnnyHK hanno migliorato il runtime estensivamente, grazie! – Javeed

+0

Questo ha risolto un grosso problema per me e mi ha permesso di smettere di "buttare l'hardware sul problema" - grazie! – James