MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Gestire le query lente in MongoDB

Quando è in produzione, un'applicazione dovrebbe fornire una risposta tempestiva all'utente allo scopo di migliorare l'interazione dell'utente con l'applicazione. A volte, tuttavia, le query del database possono iniziare a ritardare, quindi impiegare una latenza più lunga affinché una risposta raggiunga l'utente o piuttosto l'operazione di throughput è terminata a causa del superamento del timeout medio impostato.

In questo blog impareremo come identificare questi problemi in MongoDB, come risolverli ogni volta che si presentano e quali sono le possibili strategie da intraprendere affinché ciò non accada di nuovo.

Più spesso, ciò che porta a risposte alle query lente è la capacità della CPU ridotta che non è in grado di resistere al working set sottostante. Il working set in questo caso è la quantità di dati e indici che saranno soggetti a un'istanza di throughput quindi attiva in quel momento. Ciò è particolarmente considerato nella pianificazione della capacità quando ci si aspetta che la quantità di dati coinvolti aumenti nel tempo e il numero di utenti che interagiscono con la tua piattaforma.

Identificazione di un problema di query lente

Ci sono due modi per identificare le query lente in MongoDB.

  1. Utilizzo del Profiler
  2. Utilizzo dell'helper db.currentOp()

Utilizzo di MongoDB Profiler

Il profiler del database in MongoDB è un meccanismo per raccogliere informazioni dettagliate sui comandi del database eseguiti su un'istanza mongod in esecuzione, ovvero:operazioni di throughput (Crea, Leggi, Aggiorna ed Elimina) e i comandi di configurazione e amministrazione.

Il profiler utilizza una raccolta limitata denominata system.profile dove scrive tutti i dati. Ciò significa che, quando la raccolta è piena in termini di dimensioni, i documenti più vecchi vengono eliminati per dare spazio a nuovi dati.

Il Profiler è disattivato per impostazione predefinita, ma a seconda del livello di profilazione è possibile abilitarlo su un database o su un'istanza. I possibili livelli di profilazione sono:

  • 0 - il profiler è spento quindi non raccoglie alcun dato.
  • 1 - il profiler raccoglie i dati per le operazioni che richiedono più tempo del valore di slowms
  • 2- il profiler raccoglie i dati per tutte le operazioni.

 Tuttavia, l'abilitazione della profilatura genera un impatto sulle prestazioni del database e dell'utilizzo del disco, soprattutto quando il livello di profilatura è impostato su 2 . È necessario considerare eventuali implicazioni sulle prestazioni prima di abilitare e configurare il profiler su una distribuzione di produzione.

Per impostare la profilatura, utilizziamo l'helper db.setProfilingLevel() come:

db.setProfilingLevel(2)

Un documento di esempio che verrà archiviato nella raccolta system.profile sarà:

{ "was" : 0, "slowms" : 100, "sampleRate" : 1.0, "ok" : 1 }

La coppia chiave-valore "ok":1 indica che l'operazione è riuscita mentre slowms è il tempo di soglia in millisecondi che un'operazione dovrebbe impiegare e per impostazione predefinita è 100 ms.

Per modificare questo valore

db.setProfilingLevel(1, { slowms: 50 })

Per interrogare i dati sull'esecuzione della raccolta system.profile:

db.system.profile.find().pretty()

Utilizzo di db.currentOp() helper

Questa funzione elenca le query correnti in esecuzione con informazioni molto dettagliate come per quanto tempo sono state eseguite. Su una shell mongo in esecuzione, esegui il commento, ad esempio:

db.currentOp({“secs_running”:{$gte:5}}) 

Dove secs_running è la strategia di filtraggio in modo che vengano restituite solo le operazioni che hanno richiesto più di 5 secondi per essere eseguite, riducendo l'output. Viene spesso utilizzato quando lo stato della CPU può essere valutato al 100% a causa dell'impatto negativo sulle prestazioni che potrebbe implicare sul database. Quindi, modificando i valori, imparerai quali query richiedono molto tempo per essere eseguite.

I documenti restituiti hanno come chiavi di interesse:

  • interrogazione :cosa comporta la query
  • attivo : se la query è ancora in corso.
  • ns :nome della raccolta su cui eseguire la query
  • secondi_running : la durata della query in secondi in secondi

Evidenziando quali query richiedono molto tempo, hai identificato cosa sta sovraccaricando la CPU.

Interpretazione dei risultati e risoluzione dei problemi

 Come abbiamo descritto sopra, la latenza delle query dipende molto dalla quantità di dati coinvolti, che altrimenti porteranno a piani di esecuzione inefficienti. Vale a dire, ad esempio, se non utilizzi indici nella tua raccolta e desideri aggiornare determinati record, l'operazione deve esaminare tutti i documenti anziché filtrare solo quelli che corrispondono alla specifica della query. Logicamente, ciò richiederà più tempo, quindi porta a una query lenta. Puoi esaminare un piano di esecuzione inefficiente eseguendo: spiega('executionStats') che fornisce statistiche sulle prestazioni della query. Da questo punto puoi imparare come la query utilizza l'indice oltre a fornire un indizio se l'indice è ottimale.

Se l'assistente di spiegazione ritorna

{

   "queryPlanner" : {

         "plannerVersion" : 1,

         ...

         "winningPlan" : {

            "stage" : "COLLSCAN",

            ...

         }

   },

   "executionStats" : {

      "executionSuccess" : true,

      "nReturned" : 3,

      "executionTimeMillis" : 0,

      "totalKeysExamined" : 0,

      "totalDocsExamined" : 10,

      "executionStages" : {

         "stage" : "COLLSCAN",

         ...

      },

      ...

   },

   ...

}

queryPlanner.winningPlan.stage:il valore della chiave COLLSCAN indica che il mongod ha dovuto scansionare l'intero documento di raccolta per identificare i risultati, quindi diventa un'operazione costosa che porta a query lente.

executionStats.totalKeysExamined:0 significa che la raccolta non utilizza la strategia di indicizzazione

Per una determinata query, il numero di documenti coinvolti dovrebbe essere vicino a zero. Se il numero di documenti è abbastanza grande ci sono due possibilità:

  1. Non utilizza l'indicizzazione con la raccolta
  2. Utilizzo di un indice non ottimale.

Per creare un indice per una raccolta, esegui il comando: 

db.collection.createIndex( { quantity: 1 } )

Dove la quantità è un campo di esempio che hai selezionato per essere ottimale per la strategia di indicizzazione.

Se vuoi saperne di più sull'indicizzazione e su quale strategia di indicizzazione utilizzare, controlla su questo blog

Conclusione

Il degrado delle prestazioni del database può essere facilmente rappresentato da query lente, che è la minima aspettativa che vorremmo che gli utenti della piattaforma incontrassero. È possibile identificare query lente in MongoDB abilitando il profiler e configurandolo in base ad alcune specifiche o eseguendo db.currentOp() su un'istanza mongod in esecuzione.

Guardando i parametri temporali sul risultato restituito, possiamo identificare quali query sono in ritardo. Dopo aver identificato queste query, utilizziamo l'helper di spiegazione su queste query per ottenere maggiori dettagli, ad esempio se la query utilizza un indice.

Senza indicizzazione, le operazioni diventano costose poiché è necessario scansionare molti documenti prima di applicare le modifiche. Con questa battuta d'arresto, la CPU verrà sovraccaricata, con conseguenti query lente e picchi di CPU in aumento.

L'errore principale che porta a query lente è la pianificazione dell'esecuzione inefficiente che può essere facilmente risolta utilizzando un indice con la raccolta coinvolta.