Come monitorare le prestazioni di MongoDB

L’autore ha selezionato il Fondo per l’Internet Aperto/Libertà di Parola per ricevere una donazione nell’ambito del programma Scrivi per le Donazioni.

Introduzione

Il monitoraggio è una parte fondamentale dell’amministrazione del database, poiché ti consente di comprendere le prestazioni e la salute complessiva del tuo database. Monitorando le prestazioni del tuo database puoi avere una migliore percezione della sua capacità attuale, osservare come cambia il suo carico di lavoro nel tempo e pianificare in anticipo per ridimensionare il database una volta che inizia ad avvicinarsi ai suoi limiti. Può anche aiutarti a notare problemi hardware sottostanti o comportamenti anomali come un improvviso picco nell’uso del database. Infine, il monitoraggio può aiutare a diagnosticare problemi con le applicazioni che utilizzano il database, come le query dell’applicazione che causano colli di bottiglia.

MongoDB viene installato con una varietà di strumenti e utilità che puoi utilizzare per osservare le prestazioni del tuo database. In questo tutorial, imparerai come monitorare le metriche del database su richiesta utilizzando comandi e strumenti integrati. Diventerai anche familiare con il profiler del database di MongoDB che può aiutarti a individuare query scarsamente ottimizzate.

Prerequisiti

Per seguire questo tutorial, avrai bisogno di:

  • A server with a regular, non-root user with sudo privileges and a firewall configured with UFW. This tutorial was validated using a server running Ubuntu 20.04, and you can prepare your server by following this initial server setup tutorial for Ubuntu 20.04.
  • MongoDB installato sul tuo server. Per configurarlo, segui il nostro tutorial su Come Installare MongoDB su Ubuntu 20.04.
  • Un’istanza di MongoDB sicura sul tuo server abilitando l’autenticazione e creando un utente amministratore. Per proteggere MongoDB in questo modo, segui il nostro tutorial su Come Sicurizzare MongoDB su Ubuntu 20.04.
  • Familiarità con l’interrogazione delle collezioni MongoDB e il filtraggio dei risultati. Per imparare come utilizzare le query di MongoDB, segui la nostra guida su Come Creare Query in MongoDB.

Nota: I tutorial collegati su come configurare il tuo server, installare MongoDB e proteggere l’installazione di MongoDB si riferiscono a Ubuntu 20.04. Questo tutorial si concentra su MongoDB stesso, non sul sistema operativo sottostante. Funzionerà generalmente con qualsiasi installazione di MongoDB indipendentemente dal sistema operativo, a condizione che l’autenticazione sia stata abilitata.

Passaggio 1 — Preparazione dei Dati di Test

Per spiegare come monitorare le prestazioni di MongoDB, questo passaggio illustra come aprire la shell di MongoDB per connettersi alla tua istanza di MongoDB installata in locale e creare una collezione di esempio al suo interno.

Per creare la raccolta di esempio utilizzata in questa guida, connettersi alla shell di MongoDB come utente amministrativo. Questo tutorial segue le convenzioni del prerequisito tutorial sulla sicurezza di MongoDB e assume che il nome di questo utente amministrativo sia AdminSammy e che il suo database di autenticazione sia admin. Assicurati di modificare questi dettagli nel comando seguente per riflettere la tua configurazione:

  1. mongo -u AdminSammy -p --authenticationDatabase admin

Inserisci la password impostata durante l’installazione per accedere alla shell. Dopo aver fornito la password, vedrai il segno del prompt >.

Nota: In una nuova connessione, la shell di MongoDB si connetterà al database test per impostazione predefinita. Puoi utilizzare questo database in modo sicuro per sperimentare con MongoDB e la shell di MongoDB.

In alternativa, potresti passare a un altro database per eseguire tutti i comandi di esempio forniti in questo tutorial. Per passare a un altro database, esegui il comando use seguito dal nome del tuo database:

  1. use database_name

Il monitoraggio del database non è molto pratico o utile quando si lavora con un piccolo set di dati, poiché il sistema di database dovrà solo eseguire la scansione di alcuni record per qualsiasi query data. Per illustrare le funzionalità di monitoraggio delle prestazioni di MongoDB, avrai bisogno di un database con dati sufficienti affinché MongoDB impieghi un tempo significativo per eseguire le query.

A tal fine, gli esempi in questa guida si riferiscono a una raccolta di esempio chiamata accounts contenente un grande numero di documenti. Ogni documento rappresenta un singolo conto bancario con un saldo del conto generato casualmente. Ogni documento nella raccolta avrà una struttura come questa:

An example bank account document
{
    "number": "1000-987321",
    "currency": "USD",
    "balance": 431233431
}

Questo documento di esempio contiene le seguenti informazioni:

  • number: Questo campo rappresenta il numero di conto per il conto dato. In questa raccolta, ogni numero di conto avrà un prefisso di 1000- seguito da un identificatore numerico incrementale.
  • currency: Questo campo indica in che tipo di valuta è memorizzato il saldo di ciascun conto. Il valore della currency di ogni conto sarà o USD o EUR.
  • balance: Questo mostra il saldo per ogni conto bancario dato. In questo database di esempio, il campo balance di ogni documento avrà un valore generato casualmente.

Piuttosto che inserire manualmente un grande numero di documenti, è possibile eseguire il seguente codice JavaScript per creare contemporaneamente una raccolta chiamata accounts e inserire un milione di tali documenti al suo interno:

  1. for (let i = 1; i <= 1000000; ++i) {
  2. db.accounts.insertOne({
  3. "number": "1000-" + i,
  4. "currency": i > 500000 ? "USD" : "EUR",
  5. "balance": Math.random() * 100000
  6. })
  7. }

Questo codice esegue un ciclo for che si ripete un milione di volte. Ogni volta che il ciclo si ripete, esegue il metodo insertOne() sulla raccolta degli account per inserire un nuovo documento. Ad ogni iterazione, il metodo assegna un valore al campo number composto dal prefisso 1000- con il valore contenuto nella variabile i per quella iterazione. Questo significa che la prima volta che questo ciclo si ripete, il valore del campo number sarà impostato su 1000-1; l’ultima volta che si ripete, sarà impostato su 1000-1000000.

La valuta è sempre rappresentata come USD per gli account con numeri superiori a 500000 e come EUR per gli account con numeri inferiori a tale valore. Il campo bilancio utilizza la funzione Math.random() per generare un numero casuale compreso tra 0 e 1, e quindi moltiplica il numero casuale per 100000 per fornire valori più grandi.

Nota: Eseguire questo ciclo può richiedere molto tempo, anche oltre i 10 minuti. È sicuro lasciare l’operazione in esecuzione fino al termine.

L’output ti informerà del successo e restituirà l’ObjectId dell’ultimo documento inserito:

Output
{ "acknowledged" : true, "insertedId" : ObjectId("61a38a4beedf737ac8e54e82") }

Puoi verificare che i documenti siano stati inseriti correttamente eseguendo il metodo count() senza argomenti, che recupererà il conteggio dei documenti nella raccolta:

  1. db.accounts.count()
Output
1000000

In questo passaggio, hai creato con successo l’elenco dei documenti di esempio che serviranno come dati di test utilizzati in questa guida per spiegare gli strumenti forniti da MongoDB per il monitoraggio delle prestazioni. Nel prossimo passaggio, imparerai come verificare le statistiche di utilizzo di base del server.

Passaggio 2 — Verifica delle statistiche sull’utilizzo del server

MongoDB traccia automaticamente una serie di utili statistiche sulle prestazioni e controllarle regolarmente è un modo fondamentale per monitorare il tuo database. Tieni presente che queste statistiche non offriranno una visione in tempo reale di ciò che sta accadendo con il tuo database, ma possono essere utili per determinare come si comporta il database e se ci sono eventuali problemi imminenti.

Avviso: I comandi di monitoraggio di MongoDB descritti in questa guida restituiscono informazioni potenzialmente sensibili sul tuo database e sulle sue prestazioni. Per questo motivo, alcuni di questi comandi richiedono autorizzazioni avanzate.

In particolare, il metodo serverStatus() descritto in questo passaggio, così come i comandi mongostat e mongotop evidenziati nel passaggio successivo, richiedono agli utenti di essere stati concessi il ruolo clusterMonitor per poterli eseguire. Allo stesso modo, il metodo setProfilingLevel() descritto nel Passaggio 4 richiede il ruolo dbAdmin.

Presumendo di aver seguito il tutorial preliminare su Come proteggere MongoDB su Ubuntu 20.04 e di essere connesso alla tua istanza di MongoDB come utente amministrativo creato in quella guida, dovrai concedere a questo utente i ruoli aggiuntivi per seguire gli esempi in questa guida.

Prima, passa al database di autenticazione dell’utente. Questo è admin nell’esempio seguente, ma connettiti al proprio database di autenticazione dell’utente se diverso:

  1. use admin
Output
switched to db admin

Quindi esegui un metodo grantRolesToUser() e concede all’utente il ruolo clusterMonitor insieme al ruolo dbAdmin sul database in cui hai creato la collezione accounts. L’esempio seguente presume che la collezione accounts sia nel database test:

  1. db.grantRolesToUser(
  2. "AdminSammy",
  3. [
  4. "clusterMonitor",
  5. { role : "dbAdmin", db : "test" }
  6. ]
  7. )

Si noti che generalmente è considerato più sicuro avere profili utente dedicati a scopi specifici. In questo modo, nessun utente avrà privilegi eccessivamente ampi. Se si sta lavorando in un ambiente di produzione, potrebbe essere opportuno avere un utente dedicato il cui unico scopo è monitorare il database.

Nell’esempio seguente viene creato un utente MongoDB chiamato MonitorSammy e vengono loro concessi i ruoli necessari per seguire gli esempi di questo tutorial. Si noti che include anche il ruolo readWriteAnyDatabase, che consentirà a questo utente di leggere e scrivere dati in qualsiasi database nel cluster:

  1. db.createUser(
  2. {
  3. user: "MonitorSammy",
  4. pwd: passwordPrompt(),
  5. roles: [ { role : "dbAdmin", db : "test" }, "clusterMonitor", "readWriteAnyDatabase" ]
  6. }
  7. )

Dopo aver assegnato ai tuoi utenti i ruoli appropriati, torna al database dove è memorizzata la tua collezione accounts:

  1. use test
Output
switched to db test

Inizia controllando le statistiche generali del database eseguendo il metodo stats():

  1. db.stats(1024*1024)

L’argomento di questo metodo (1024*1024) è il fattore di scala e indica a MongoDB di restituire le informazioni di archiviazione in megabyte. Se ometti questo, i valori verranno presentati tutti in byte.

Il metodo stats() restituisce un output breve e conciso con alcune statistiche importanti relative al database corrente:

Output
{ "db" : "test", "collections" : 3, "views" : 0, "objects" : 1000017, "avgObjSize" : 80.8896048767171, "dataSize" : 77.14365005493164, "storageSize" : 24.109375, "indexes" : 4, "indexSize" : 9.9765625, "totalSize" : 34.0859375, "scaleFactor" : 1048576, "fsUsedSize" : 4238.12109375, "fsTotalSize" : 24635.703125, "ok" : 1 }

Questo output fornisce una panoramica dei dati che questa istanza di MongoDB sta memorizzando. Le seguenti chiavi restituite in questo output possono essere particolarmente utili:

  • La chiave objects mostra il numero totale di documenti nel database. Puoi utilizzare questo valore per valutare la dimensione del database e, quando osservato nel tempo, la sua crescita.
  • avgObjectSize mostra la dimensione media di questi documenti, offrendo informazioni su se il database sta operando su documenti grandi e complessi o su documenti piccoli. Questo valore viene sempre mostrato in byte, indipendentemente dal fatto che tu specifichi un fattore di scala.
  • Le chiavi collections e indexes indicano quante raccolte e indici sono attualmente definiti nel database.
  • La chiave totalSize indica quanta memoria di archiviazione occupa il database sul disco.

Queste informazioni restituite dal metodo stats() possono aiutarti a farti un’idea di quanti dati sono attualmente memorizzati nel tuo database, ma non forniscono informazioni sulle sue prestazioni o sui problemi esistenti. Per questo, il metodo molto più dettagliato serverStatus() risulta utile:

  1. db.serverStatus()

L’output di questo metodo è lungo e fornisce molte informazioni sull’uso del server:

Output
{ "host" : "ubuntu-mongo-rs", "version" : "4.4.6", "process" : "mongod", "pid" : NumberLong(658997), "uptime" : 976, . . . "ok" : 1 }

Sebbene tutte queste informazioni potrebbero essere potenzialmente utili, questa guida si concentrerà su tre sezioni in particolare. Prima, trova la sezione connections di questo output:

Output
. . . "connections" : { "current" : 4, "available" : 51196, "totalCreated" : 4, "active" : 2, "exhaustIsMaster" : 1, "exhaustHello" : 0, "awaitingTopologyChanges" : 1 }, . . .

Ogni server di database può supportare solo un numero limitato di connessioni contemporaneamente. La chiave current mostra il numero di client attualmente connessi al database, mentre available è il numero di connessioni non utilizzate rimanenti disponibili nel database. Il valore totalCreated contiene il numero di connessioni utilizzate dall’avvio del server.

La maggior parte delle applicazioni sono progettate per riutilizzare le connessioni esistenti e non aprirne di nuove frequentemente. Pertanto, un elevato numero di connessioni, se non previsto, può essere un segno allarmante di una configurazione errata di come i client accedono al server.

Se l’elevato numero di connessioni è previsto dal tipo di carichi di lavoro eseguiti, potresti considerare l’aggiunta di uno o più shard a un cluster sharded per distribuire il traffico su più istanze di MongoDB.

Successivamente, trova la sezione globalLock dell’output. Questa sezione si riferisce ai lock globali sull’intero server di database:

Output
. . . "globalLock" : { "totalTime" : NumberLong(975312000), "currentQueue" : { "total" : 0, "readers" : 0, "writers" : 0 }, "activeClients" : { "total" : 0, "readers" : 0, "writers" : 0 } },

MongoDB utilizza i lock per garantire la consistenza dei dati durante l’esecuzione di operazioni multiple, garantendo che nessuna query modifichi gli stessi dati contemporaneamente. Su server ad alto utilizzo, c’è la possibilità che i lock possano causare dei colli di bottiglia, con una o più query in attesa che i lock vengano rilasciati prima che possano essere eseguite.

Il valore currentQueue.total mostra il numero di query in attesa che i lock vengano rilasciati in modo che possano essere eseguite. Se questo valore è alto, significa che le prestazioni del database sono influenzate e le query impiegheranno più tempo per completarsi.

Questo spesso deriva da molte query a lungo in esecuzione che trattengono i blocchi e potrebbe essere indicativo di un uso inefficace degli indici o di query mal progettate, tra altre possibilità.

Infine, trova la sezione opcounters:

Output
"opcounters" : { "insert" : NumberLong(10000007), "query" : NumberLong(6), "update" : NumberLong(6), "delete" : NumberLong(0), "getmore" : NumberLong(0), "command" : NumberLong(1298) },

Questa sezione dell’output di serverStatus() può aiutarti a capire se il server del database viene utilizzato principalmente per letture o scritture, oppure se il suo utilizzo è ben bilanciato. In questo esempio, dopo l’inserimento dei documenti di test, il contatore delle operazioni di insert è molto più alto rispetto alle operazioni di query. In uno scenario reale, questi valori probabilmente sarebbero diversi.

I database con un carico di scrittura elevato possono beneficiare di una scalabilità orizzontale tramite sharding. Allo stesso modo, i database MongoDB con un carico di lettura elevato solitamente trarranno vantaggio dalla replicazione.

Queste statistiche possono dare un’idea generale di come viene utilizzato il server e se ci sono problemi di prestazioni come lunghe code di blocco al momento dell’accesso. Tuttavia, non forniscono informazioni in tempo reale su come viene utilizzato il server. Per questo, i comandi mongostat e mongotop sono utili strumenti.

Passaggio 3 — Utilizzo di mongostat e mongotop per Ottenere Statistiche del Database in Tempo Reale

Mentre i comandi utilizzati per accedere alle statistiche del server MongoDB possono fornire un’idea di come il server sia utilizzato in retrospect, non possono fornire informazioni in tempo reale su quali collezioni vengano utilizzate più attivamente in quel momento o su che tipo di query vengano eseguite.

MongoDB fornisce due utili strumenti di sistema per il monitoraggio in tempo reale che analizzano l’attività del database e aggiornano continuamente le informazioni che forniscono: mongostat e mongotop. mongostat fornisce una breve panoramica dello stato attuale dell’istanza di MongoDB, mentre mongotop tiene traccia di quanto tempo l’istanza impiega per operazioni di lettura e scrittura. Entrambi questi strumenti vengono eseguiti dalla riga di comando, anziché dalla shell di MongoDB.

Per utilizzare mongostat, mantieni la tua connessione corrente alla shell di MongoDB e apri un’altra finestra del terminale per accedere alla shell del server. Nella seconda shell del server, esegui il comando mongostat:

  1. mongostat -u AdminSammy --authenticationDatabase admin

Come precedentemente menzionato, mongostat richiede privilegi avanzati. Se hai abilitato l’autenticazione sulla tua istanza MongoDB e configurato un utente con i ruoli appropriati, allora dovrai autenticarti come tale utente fornendo il suo nome utente e il database di autenticazione (come mostrato in questo esempio) e quindi inserire la loro password quando richiesto.

In una configurazione predefinita, mongostat stampa i contatori delle query attualmente eseguite ad intervalli di un secondo:

Output
insert query update delete getmore command dirty used flushes vsize res qrw arw net_in net_out conn time *0 *0 *0 *0 0 1|0 0.0% 38.7% 0 1.54G 210M 0|0 1|0 223b 84.4k 7 Nov 28 15:40:40.621 *0 *0 *0 *0 0 2|0 0.0% 38.7% 0 1.54G 210M 0|0 1|0 224b 84.8k 7 Nov 28 15:40:41.619 *0 *0 *0 *0 0 1|0 0.0% 38.7% 0 1.54G 210M 0|0 1|0 223b 84.5k 7 Nov 28 15:40:42.621 *0 *0 *0 *0 0 3|0 0.0% 38.7% 0 1.54G 210M 0|0 1|0 365b 85.0k 7 Nov 28 15:40:43.619

Se l’output di mongostat mostra un valore di 0 per un determinato tipo di query, indica che il database non sta eseguendo operazioni di quel tipo. Questo output di esempio mostra 0 per ogni tipo di query, il che significa che attualmente non ci sono query attivamente in esecuzione.

Dovresti comunque avere aperta la tua prima finestra del terminale e connessa alla tua shell MongoDB. Inserisci alcuni documenti di test nella raccolta accounts e verifica se mongostat noterà l’attività:

  1. for (let i = 1; i <= 10000; ++i) {
  2. db.accounts.insertOne({
  3. "number": "2000-" + i,
  4. "currency": "USD",
  5. "balance": Math.random() * 100000
  6. })
  7. }

Questo è un ciclo for simile a quello eseguito nel Passo 1. Questa volta, però, il ciclo inserisce solo 10000 voci. I numeri di conto sono prefissati con 2000, e la valuta è sempre USD.

Mentre i nuovi documenti vengono inseriti, controlla l’output di mongostat:

Output
. . . *0 *0 *0 *0 0 1|0 0.0% 38.7% 0 1.54G 210M 0|0 1|0 112b 42.5k 4 Nov 28 15:50:33.294 *0 *0 *0 *0 0 0|0 0.0% 38.7% 0 1.54G 210M 0|0 1|0 111b 42.2k 4 Nov 28 15:50:34.295 755 *0 *0 *0 0 1|0 0.1% 38.8% 0 1.54G 210M 0|0 1|0 154k 79.4k 4 Nov 28 15:50:35.294 2853 *0 *0 *0 0 0|0 0.4% 39.1% 0 1.54G 211M 0|0 1|0 585k 182k 4 Nov 28 15:50:36.295 2791 *0 *0 *0 0 1|0 0.7% 39.4% 0 1.54G 212M 0|0 1|0 572k 179k 4 Nov 28 15:50:37.293 2849 *0 *0 *0 0 0|0 1.0% 39.7% 0 1.54G 213M 0|0 1|0 584k 182k 4 Nov 28 15:50:38.296 745 *0 *0 *0 0 2|0 1.1% 39.8% 0 1.54G 213M 0|0 1|0 153k 79.2k 4 Nov 28 15:50:39.294 *0 *0 *0 *0 0 0|0 1.1% 39.8% 0 1.54G 213M 0|0 1|0 111b 42.2k 4 Nov 28 15:50:40.295 *0 *0 *0 *0 0 2|0 1.1% 39.8% 0 1.54G 213M 0|0 1|0 167b 42.7k 4 Nov 28 15:50:41.293 . . .

Mentre la query è in esecuzione, le nuove righe restituite da mongostat iniziano a mostrare valori diversi da 0. Nella colonna insert che mostra il numero di query che stanno inserendo nuovi dati nel database, i valori erano più alti per diversi secondi. Poiché mongostat mostra i dati in intervalli di un secondo, è possibile trovare non solo la proporzione di inserimenti rispetto ad altri tipi di operazioni sul database, ma anche quanto velocemente il database inserisce i nuovi dati. In questo esempio, il server ha raggiunto quasi 3000 inserimenti al secondo.

Puoi utilizzare mongostat per monitorare il carico di lavoro attuale del server del database, raggruppato per tipi di query. Il secondo strumento fornito da MongoDB – mongotop – mostra l’attività del server del database raggruppata per collezioni.

Arresta l’esecuzione di mongostat nella tua seconda finestra del terminale premendo CTRL + C. Quindi esegui mongotop nella stessa finestra del terminale. Di nuovo, se hai l’autenticazione abilitata, dovrai autenticarti come utente con i privilegi appropriati:

  1. mongotop -u AdminSammy --authenticationDatabase admin

mongotop restituisce un elenco di tutte le collezioni nel database, accompagnate dal tempo trascorso per le letture, scritture e in totale all’interno della finestra temporale. Similmente a mongostat, l’output viene aggiornato ogni secondo:

Output
2021-11-28T15:54:42.290+0000 connected to: mongodb://localhost/ ns total read write 2021-11-28T15:54:43Z admin.system.roles 0ms 0ms 0ms admin.system.version 0ms 0ms 0ms config.system.sessions 0ms 0ms 0ms config.transactions 0ms 0ms 0ms local.system.replset 0ms 0ms 0ms test.accounts 0ms 0ms 0ms . . .

Prova ad inserire altri documenti nel database per vedere se l’attività viene registrata in mongotop. Nella shell di MongoDB, esegui il seguente ciclo for; dopo averlo fatto, osserva la finestra del terminale con mongotop in esecuzione:

  1. for (let i = 1; i <= 10000; ++i) {
  2. db.accounts.insertOne({
  3. "number": "3000-" + i,
  4. "currency": "USD",
  5. "balance": Math.random() * 100000
  6. })
  7. }

Questa volta, l’attività sarà visibile nelle statistiche di mongotop.

Output
. . . ns total read write 2021-11-28T15:57:27Z test.accounts 127ms 0ms 127ms admin.$cmd.aggregate 0ms 0ms 0ms admin.system.roles 0ms 0ms 0ms admin.system.version 0ms 0ms 0ms config.system.sessions 0ms 0ms 0ms config.transactions 0ms 0ms 0ms local.system.replset 0ms 0ms 0ms ns total read write 2021-11-28T15:57:28Z test.accounts 130ms 0ms 130ms admin.$cmd.aggregate 0ms 0ms 0ms admin.system.roles 0ms 0ms 0ms admin.system.version 0ms 0ms 0ms config.system.sessions 0ms 0ms 0ms config.transactions 0ms 0ms 0ms local.system.replset 0ms 0ms 0ms . . .

Qui, mongotop mostra che tutta l’attività del database è avvenuta nella collezione accounts nel database test e che tutte le operazioni nel periodo di tempo sono state operazioni di scrittura. Tutto questo dovrebbe essere in linea con l’operazione di loop for eseguita.

Come con mongostat, puoi interrompere l’esecuzione di mongotop premendo CTRL + C.

Quando osservato durante il carico massimo, puoi utilizzare mongotop per monitorare come l’attività del database si diffonde tra le diverse collezioni per aiutarti a comprendere meglio lo schema e pianificare la scalabilità. Fornisce anche informazioni su se l’utilizzo di una collezione sia più orientato alla lettura o alla scrittura.

Passaggio 4 — Utilizzo del Profiler del Database di MongoDB per Identificare Query Lente

I colli di bottiglia delle prestazioni del database possono derivare da molte fonti. Anche se il ridimensionamento del database (orizzontalmente o verticalmente) è spesso la soluzione ai colli di bottiglia delle prestazioni, la loro causa potrebbe non essere effettivamente i limiti del database ma problemi con lo schema o la progettazione della query.

Se le query vengono eseguite per troppo tempo, la causa potrebbe essere un uso inefficace degli indici o errori nella query stessa. Le query a lunga durata spesso passano inosservate durante lo sviluppo dell’applicazione, tipicamente perché i set di dati di test sono troppo piccoli o le condizioni sono diverse rispetto alla produzione.

Potresti potenzialmente individuare il colpevole eseguendo manualmente query di test e verificando quali di esse hanno prestazioni scadenti, anche se ciò sarebbe molto noioso. Fortunatamente, lo strumento di profilazione del database di MongoDB può farlo automaticamente.

Lo strumento di profilazione del database di MongoDB può registrare query e statistiche sulla loro esecuzione quando soddisfano determinate condizioni. La condizione più importante è il tempo di esecuzione della query: se una query impiega più tempo del previsto per eseguirsi, il profiler segnalerà automaticamente quella query come problematica. Utilizzando il profiler, puoi identificare quali query hanno prestazioni scadenti e concentrarti sulla risoluzione di tali problemi particolari.

Prima di utilizzare il profiler, esegui la seguente query. Questa query recupererà uno degli account che hai inserito, anche se non è così semplice come potrebbe sembrare a prima vista:

  1. db.accounts.find({"number": "1000-20"})

Il comando recupererà l’account esatto che hai richiesto:

Output
{ "_id" : ObjectId("61a38fd5eedf737ac8e54e96"), "number" : "1000-20", "currency" : "EUR", "balance" : 24101.14770458518 }

Potresti aver notato che la query non è stata eseguita immediatamente e che ci è voluto un momento o due a MongoDB per trovare l’account. In un’applicazione del mondo reale, potrebbero esserci molti tipi di query che hanno prestazioni scadenti e potresti non notare le loro prestazioni scadenti nella pratica.

Puoi configurare MongoDB per aiutarti a individuare quali query impiegano più tempo del previsto. Per farlo, abilita prima il profiler eseguendo il seguente comando:

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

Il metodo setProfilingLevel() accetta due argomenti. Il primo è il livello di profilazione, che può essere 0, 1 o 2:

  • 0 disabilita il profiler
  • 1 abilita il profiler solo su query lente che soddisfano la condizione
  • Il codice 2 abilita il profiler per tutte le query

In questo esempio, il profiler analizzerà le query che impiegano più di 100 millisecondi, come definito dal secondo argomento, { slowms: 100 }.

Nota: L’uso del profiler degrada le prestazioni, poiché MongoDB deve ora analizzare le query oltre ad eseguirle. Dovrebbe essere utilizzato con parsimonia durante il monitoraggio dei colloqui di bottiglia delle prestazioni.

È possibile personalizzare ulteriormente il sottoinsieme di query che il profiler registrerà configurandolo per profilare solo una certa percentuale di query o filtrando per tipo di query. Per saperne di più su come è possibile avere un maggiore controllo sul profiler, fare riferimento alla documentazione ufficiale sull’argomento.

Questo metodo restituirà un messaggio di successo:

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

Da questo momento in poi, il profiling del database sarà abilitato e MongoDB monitorerà attivamente ogni query che si esegue per individuare quelle che impiegano più di 100 millisecondi per completarsi.

Prova questo eseguendo alcune query diverse. Prima, utilizza il comando count per trovare il numero di documenti nella raccolta accounts:

  1. db.accounts.count()

Questo comando restituirà rapidamente il numero di documenti nella raccolta:

Output
1020000

Quindi, prova a cercare i primi tre conti bancari che appaiono nella raccolta:

  1. db.accounts.find().limit(3)

Anche in questo caso, il database restituirà rapidamente i risultati:

Output
{ "_id" : ObjectId("61ef40640f2ba52efc56ee17"), "number" : "1000-1", "currency" : "EUR", "balance" : 25393.132960293842 } { "_id" : ObjectId("61ef40640f2ba52efc56ee18"), "number" : "1000-2", "currency" : "EUR", "balance" : 63629.42056192393 } { "_id" : ObjectId("61ef40640f2ba52efc56ee19"), "number" : "1000-3", "currency" : "EUR", "balance" : 75602.12331602155 }

Infine, esegui nuovamente la query di ricerca per il particolare conto bancario:

  1. db.accounts.find({"number": "1000-20"})

Questa query restituirà il risultato ma, come prima, ci vorrà un momento o due in più rispetto alle operazioni precedenti:

Output
{ "_id" : ObjectId("61a38fd5eedf737ac8e54e96"), "number" : "1000-20", "currency" : "EUR", "balance" : 24101.14770458518 }

Il profiler non produce alcun output proprio anche se la query è visibilmente più lenta. Invece, i dettagli sulle operazioni lente vengono registrati in una collezione speciale all’interno del database chiamata system.profile. Questa collezione è una collezione limitata che non supera mai 1 MB di dimensione. Ciò significa che conterrà sempre un elenco solo delle query più recenti.

Per recuperare le informazioni sulle query identificate dal profiler, è necessario interrogare la collezione system.profile in modo simile a questo:

  1. db.system.profile.find().sort({ "ts" : -1 }).pretty()

Questa query utilizza il metodo find(), come al solito. Include anche una clausola sort che contiene {"ts": -1} come argomento. Questo ordinerà il set di risultati con le query più recenti per prime. Infine, il metodo pretty() alla fine visualizzerà l’output in un formato più leggibile.

Ogni query lenta è rappresentata come un documento regolare, e system.profile è come una qualsiasi altra collezione regolare. Ciò significa che è possibile filtrare i risultati, ordinarli e persino usarli in pipeline di aggregazione per restringere ulteriormente o analizzare l’elenco di query identificate dal profiler.

Nota che il risultato consiste solo di un singolo documento. Le altre due query sono state eseguite abbastanza velocemente da non attivare il profiler:

Output
{ "op" : "query", "ns" : "test.accounts", "command" : { "find" : "accounts", "filter" : { "number" : "1000-20" }, . . . }, "nreturned" : 1, "keysExamined" : 0, "docsExamined" : 1030000, . . . "millis" : 434, "planSummary" : "COLLSCAN", . . . }

Questo output fornisce diversi dettagli sull’esecuzione della query lenta:

  • La chiave op mostra quale tipo di operazione rappresenta queste informazioni. Qui, è una query, poiché rappresenta un’operazione in cui hai usato il metodo find() per recuperare i dati dal database.
  • La chiave ns indica quale database e collezione sono stati coinvolti nell’operazione. Come mostra l’output, questa operazione ha interrogato la collezione accounts nel database test.
  • La chiave command fornisce ulteriori informazioni sulla query stessa. In questo caso, il sottochiave filter contiene l’intero documento di filtro. Utilizzando le informazioni provenienti dai campi op e command, è possibile ricostruire la query in questione.
  • Nel campo millis, troverai il tempo esatto impiegato per completare la query. In questo esempio, quasi mezzo secondo.
  • Il campo docsExamined fornisce il numero di documenti scansionati per restituire il set di risultati.
  • nreturned rappresenta il numero di documenti restituiti dalla query. In questo esempio, è stato restituito un solo documento su oltre un milione scansionati.
  • Il planSummary mostra il metodo utilizzato da MongoDB per eseguire la query. COLLSCAN corrisponde a una scansione completa della collezione, il che significa che ha esaminato ogni documento nella collezione uno per uno per trovare il conto bancario corrispondente.

Tutte insieme, queste informazioni sottolineano la necessità di un indice che potrebbe aiutare MongoDB ad eseguire questa query più velocemente. Il database doveva esaminare l’intera raccolta per trovare un singolo documento, come indicato dalla grande differenza tra il numero di documenti esaminati e quelli restituiti, così come la strategia di esecuzione.

In questo particolare esempio, la creazione di un indice per supportare le query che filtrano i dati basandosi sul campo number fornirebbe un immediato aumento delle prestazioni di questi tipi di query. In scenari reali, le soluzioni per le query lente possono essere diverse e dipendono dalla query esatta che sta causando problemi.

Per terminare la sessione di profilatura, è possibile disabilitare il profiler impostando il livello di profilatura a zero:

  1. db.setProfilingLevel(0)

L’operazione avrà successo con un messaggio di conferma:

Output
{ "was" : 1, "slowms" : 100, "sampleRate" : 1, "ok" : 1 }

Ora il database torna al funzionamento normale senza alcuna profilatura in background.

Quando sospetti che le query lente possano avere un impatto negativo sulle prestazioni del tuo database, puoi utilizzare il profiler del database per trovarle e comprendere meglio la loro struttura e come vengono eseguite. Con queste informazioni, sarai meglio attrezzato per modificarle e migliorarne le prestazioni.

Conclusione

Seguendo questa guida, hai imparato come trovare le statistiche del server MongoDB e come utilizzare strumenti di diagnostica come mongotop, mongostat, oltre al meccanismo di profilazione del database di MongoDB. Puoi utilizzarli per avere una migliore comprensione del carico di lavoro del tuo database, determinare quali collezioni sono le più attive e se il server esegue principalmente scritture o letture. Puoi anche identificare query lente che influenzano le prestazioni di MongoDB al fine di sostituirle con query più efficienti.

Questi sono solo una selezione di strumenti e tecniche che puoi utilizzare per monitorare la salute e le prestazioni della tua installazione di MongoDB e agire di conseguenza. Ciascuno di questi strumenti può essere ulteriormente configurato e personalizzato per fornirti una visione più mirata delle prestazioni del server. Ti incoraggiamo a studiare la documentazione ufficiale di MongoDB per saperne di più sulle tecniche che puoi utilizzare per monitorare le prestazioni del server e agire di conseguenza.

Source:
https://www.digitalocean.com/community/tutorials/how-to-monitor-mongodb-s-performance