Scopri i metodi pratici di Brendan Gregg (USE, RED, flame graphs) per indagare la latenza e i colli di bottiglia in produzione con dati, non con supposizioni.

Brendan Gregg è una delle voci più influenti nelle prestazioni dei sistemi, specialmente nell'ambito Linux. Ha scritto libri molto usati, creato strumenti pratici e — soprattutto — condiviso metodi chiari per investigare problemi reali in produzione. I team adottano il suo approccio perché funziona sotto pressione: quando la latenza sale e tutti vogliono risposte, serve un modo per passare da “forse è X” a “è sicuramente Y” con il minimo clamore.
Una metodologia di performance non è un singolo strumento o un comando intelligente. È un modo ripetibile di investigare: una checklist su cosa guardare per primo, come interpretare ciò che vedi e come decidere il passo successivo.
Questa ripetibilità è ciò che riduce le supposizioni. Invece di affidarci a chi ha più intuito (o all'opinione più forte), seguiamo un processo coerente che:
Molte indagini sulla latenza vanno storto nei primi cinque minuti. Si passa subito alle soluzioni: “aggiungi CPU”, “riavvia il servizio”, “aumenta la cache”, “tweaka il GC”, “dev'essere la rete”. A volte queste azioni aiutano—spesso però nascondono il segnale, sprecano tempo o introducono nuovo rischio.
I metodi di Gregg ti spingono a rimandare le “soluzioni” finché non puoi rispondere a domande più semplici: cosa è satura? cosa genera errori? cosa è rallentato — il throughput, la coda o le singole operazioni?
Questa guida ti aiuta a restringere l'ambito, misurare i segnali giusti e confermare il collo di bottiglia prima di ottimizzare. L'obiettivo è un workflow strutturato per investigare problemi di latenza e di profiling in produzione, così i risultati non dipendono dalla fortuna.
La latenza è un sintomo: gli utenti aspettano più a lungo che il lavoro finisca. La causa di solito è altrove — contesa CPU, attese su disco o rete, contesa di lock, garbage collection, code o ritardi in dipendenze remote. Misurare solo la latenza ti dice che c'è un dolore, non da dove proviene.
Questi tre segnali sono collegati:
Prima di ottimizzare, cattura tutti e tre per la stessa finestra temporale. Altrimenti potresti “risolvere” la latenza eliminando lavoro o facendo fallire più rapidamente.
La latenza media nasconde i picchi che gli utenti ricordano. Un servizio con una media di 50 ms può comunque avere frequenti stall da 2 s.
Monitora i percentili:
Osserva anche la forma della latenza: un p50 stabile con p99 in aumento spesso indica stall intermittenti (per esempio contesa su lock, problemi I/O, pause stop-the-world) piuttosto che un rallentamento generale.
Un budget di latenza è un modello di rendiconto semplice: “se la richiesta deve finire in 300 ms, come può essere speso quel tempo?” Scomponilo in cassette come:
Questo budget inquadra il primo compito di misura: identifica quale bucket è cresciuto durante il picco, quindi indaga quella area invece di ottimizzare alla cieca.
Il lavoro sulla latenza deraglia quando il “problema” è descritto come il sistema è lento. I metodi di Gregg partono prima: costringono a trasformare il problema in una domanda specifica e verificabile.
Scrivi due frasi prima di toccare strumenti:
Questo evita di ottimizzare lo strato sbagliato — per esempio la CPU dell'host — quando il dolore è isolato a un endpoint o a una dipendenza a valle.
Scegli una finestra che corrisponda al reclamo e includa, se possibile, un periodo di confronto “buono”.
Definisci esplicitamente l'ambito dell'indagine:
Essere precisi qui rende i passi successivi (USE, RED, profiling) più veloci perché saprai quali dati dovrebbero cambiare se la tua ipotesi è corretta.
Annota deploy, cambi di configurazione, shift di traffico ed eventi infrastrutturali—ma non presumere causalità. Scrivili come “Se X, allora ci aspetteremmo Y”, così puoi confermare o rifiutare rapidamente.
Un piccolo registro evita lavoro duplicato tra i membri del team e rende i passaggi più semplici da trasferire.
Time | Question | Scope | Data checked | Result | Next step
Anche cinque righe come queste possono trasformare un incidente stressante in un processo ripetibile.
Il Metodo USE (Utilization, Saturation, Errors) è la checklist rapida di Gregg per scandagliare le “quattro grandi” risorse — CPU, memoria, disco (storage) e rete — così puoi smettere di indovinare e iniziare a restringere il problema.
Invece di fissare decine di dashboard, poni le stesse tre domande per ogni risorsa:
Applicato con costanza, diventa un inventario rapido di dove esiste “pressione”.
Per la CPU, utilization è la percentuale di CPU occupata, saturation appare come pressione della run-queue o thread in attesa di esecuzione, e gli errori possono includere throttling (nelle container) o interrupt mal gestiti.
Per la memoria, utilization è memoria usata, saturation si manifesta come paging o garbage collection frequente, e gli errori includono fallimenti di allocazione o eventi OOM.
Per il disco, utilization è il tempo device busy, saturation è la profondità della coda e il tempo di attesa read/write, e gli errori sono I/O error o timeout.
Per la rete, utilization è throughput, saturation sono drop/code/latenza, e gli errori sono retransmit, reset o perdita di pacchetti.
Quando gli utenti segnalano lentezza, i segnali di saturation sono spesso i più rivelatori: code, tempo di attesa e contesa tendono a correlare più direttamente con la latenza rispetto al solo utilizzo.
Le metriche a livello di servizio (come latenza delle richieste e tasso di errore) ti dicono impatto. USE ti dice dove guardare dopo identificando quale risorsa soffre.
Un ciclo pratico è:
Il metodo RED ti tiene ancorato all'esperienza utente prima di tuffarti nei grafici host.
RED ti impedisce di inseguire metriche di sistema “interessanti” che non impattano gli utenti. Ti forza a un ciclo più stretto: quale endpoint è lento, per quali utenti e da quando? Se Duration sale solo su una route mentre la CPU globale è piatta, hai già un punto di partenza più preciso.
Una buona abitudine: mantieni RED suddiviso per servizio e endpoint principali (o RPC chiave). Così distingui facilmente un degrado ampio da una regressione localizzata.
RED ti dice dove fa male. USE ti aiuta a testare quale risorsa è responsabile.
Esempi:
Mantieni il layout focalizzato:
Se vuoi un workflow di incidente coerente, abbina questa vista all'inventario USE in /blog/use-method-overview così puoi passare da “gli utenti lo percepiscono” a “questa risorsa è il vincolo” con meno caos.
Un'indagine sulle prestazioni può esplodere in decine di grafici e ipotesi in pochi minuti. La mentalità di Gregg è mantenerla ristretta: il tuo lavoro non è “raccogliere più dati”, ma porre la prossima domanda che elimina più rapidamente l'incertezza.
La maggior parte dei problemi di latenza è dominata da un singolo costo (o da una coppia): un lock caldo, una dipendenza lenta, un disco sovraccarico, un pattern di pause GC. Prioritizzare significa cercare prima quel costo dominante, perché ridurre del 5% cinque parti diverse difficilmente migliora la latenza percepita.
Una prova pratica: “Cosa potrebbe spiegare la maggior parte della variazione di latenza che vediamo?” Se un'ipotesi ne spiega solo una piccola fetta, è di bassa priorità.
Usa un approccio top-down quando devi rispondere “Gli utenti sono impattati?” Parti dagli endpoint (segnali in stile RED): latenza, throughput, errori. Questo evita di ottimizzare qualcosa che non è sul percorso critico.
Usa un approccio bottom-up quando l'host è chiaramente malato (sintomi USE): CPU satura, memoria fuori controllo, I/O atteso. Se un nodo è bloccato, perderai tempo a guardare percentili di endpoint senza capire il vincolo.
Quando scatta un alert, scegli un ramo e resta su quello finché non lo confermi o lo scarti:
Limitati a un piccolo set iniziale di segnali, poi approfondisci solo quando qualcosa si muove. Se ti serve una checklist per mantenere il focus, collega i passi a un runbook come /blog/performance-incident-workflow così ogni nuova metrica ha uno scopo: rispondere a una domanda specifica.
Il profiling in produzione può sembrare rischioso perché tocca il sistema live — ma spesso è il modo più veloce per sostituire il dibattito con l'evidenza. Log e dashboard possono dirti che qualcosa è lento. Il profiling ti dice dove va il tempo: quali funzioni sono calde, quali thread aspettano e quali percorsi di codice dominano durante l'incidente.
Il profiling è uno strumento di “budget del tempo”. Invece di dibattere teorie (“è il database” vs “è il GC”), ottieni evidenze come “il 45% dei campioni CPU era nel parsing JSON” o “la maggior parte delle richieste è bloccata su un mutex”. Questo restringe il passo successivo a una o due correzioni concrete.
Ognuno risponde a una domanda diversa. Alta latenza con poca CPU spesso indica off-CPU o contesa di lock piuttosto che hotspot CPU.
Molti team partono on-demand, poi passano al always-on quando si fidano della sicurezza e vedono problemi ricorrenti.
Il profiling sicuro in produzione riguarda il controllo del costo. Preferisci il campionamento (non tracciare ogni evento), mantieni le finestre di cattura brevi (per esempio 10–30 secondi) e misura l'overhead in un canary prima. Se sei insicuro, parti con campionamento a bassa frequenza e aumenta solo se il segnale è troppo rumoroso.
I flame graph visualizzano dove il tempo campionato è andato durante una finestra di profiling. Ogni “box” è una funzione (o frame di stack) e ogni stack mostra come l'esecuzione è arrivata a quella funzione. Sono eccellenti per individuare pattern rapidamente — ma non dicono automaticamente “qui c'è il bug”.
Un flame graph rappresenta di solito campioni on-CPU: tempo in cui il programma stava effettivamente girando su un core. Può evidenziare percorsi CPU-costosi, parsing inefficiente, serializzazione e hotspot che consumano CPU.
Non mostra direttamente attese su disco, rete, scheduler o tempo bloccato su mutex (quello è off-CPU e richiede profiling diverso). Non prova neppure la causalità rispetto alla latenza utente a meno che non lo leghi a una domanda circoscritta.
La box più larga è tentante da incolpare, ma chiediti: è uno hotspot che puoi cambiare o solo “tempo speso in malloc, GC o logging” perché il vero problema è a monte? Fai attenzione anche al contesto mancante (JIT, inlining, simboli) che può far sembrare una box colpevole quando è solo il messaggero.
Tratta un flame graph come risposta a una domanda circoscritta: quale endpoint, quale finestra temporale, quali host e cosa è cambiato. Confronta flame graph “prima vs dopo” (o “sano vs degradato”) per lo stesso percorso di richiesta per evitare rumore di profiling.
Quando la latenza sale, molti team guardano prima la CPU%. È comprensibile — ma spesso porta nella direzione sbagliata. Un servizio può avere “solo il 20% di CPU” e risultare comunque dolorosamente lento se i suoi thread passano la maggior parte del tempo a non essere in esecuzione.
La CPU% risponde a “quanto è impegnato il processore?” Non risponde a “dove è andato il tempo della mia richiesta?” Le richieste possono bloccarsi mentre i thread aspettano, sono bloccati o parcheggiati dallo scheduler.
Un'idea chiave: il tempo di muro di una richiesta include sia lavoro on-CPU sia attese off-CPU.
Il tempo off-CPU spesso si nasconde dietro dipendenze e contese:
Alcuni segnali correlano spesso a colli off-CPU:
Questi sintomi dicono “stiamo aspettando”, ma non cosa stiamo aspettando.
Il profiling off-CPU attribuisce tempo al motivo per cui non stavamo girando: bloccati in syscall, in attesa di lock, in sleep o deschedulati. Questo è potente per la latenza perché trasforma rallentamenti vaghi in categorie azionabili: “bloccato su mutex X”, “in attesa di read() dal disco” o “impantanato in connect() verso un upstream”. Una volta che puoi nominare l'attesa, puoi misurarla, confermarla e correggerla.
Il lavoro sulle prestazioni fallisce spesso nello stesso punto: qualcuno vede una metrica sospetta, la dichiara “il problema” e inizia a tuning. I metodi di Gregg ti spingono a rallentare e provare cosa limita il sistema prima di cambiare qualsiasi cosa.
Un collo di bottiglia è la risorsa o componente che attualmente limita il throughput o guida la latenza. Se lo allevi, gli utenti vedranno miglioramento.
Un hot spot è dove si spende tempo (per esempio una funzione che appare spesso in un profilo). Gli hotspot possono essere veri colli di bottiglia — oppure semplice lavoro che non impatta il percorso lento.
Il rumore è tutto ciò che sembra significativo ma non lo è: job in background, picchi isolati, artefatti di campionamento, effetti di cache o “top talkers” che non correlano col problema visibile all'utente.
Inizia catturando un clean prima: il sintomo utente (latenza o error rate) e i segnali principali sospetti (saturazione CPU, profondità code, I/O disco, contesa lock, ecc.). Poi applica un cambiamento controllato che dovrebbe influenzare solo la causa sospettata.
Esempi di test causali:
La correlazione è un indizio, non una sentenza. Se “la CPU sale quando la latenza sale”, verifica cambiando la disponibilità CPU o riducendo il lavoro CPU e osserva se la latenza segue.
Annota: cosa è stato misurato, la modifica esatta fatta, i risultati prima/dopo e il miglioramento osservato. Questo trasforma un successo isolato in un playbook riutilizzabile per il prossimo incidente — e impedisce che l’intuizione riscriva la storia dopo l'evento.
Gli incidenti prestazionali sembrano urgenti, ed è proprio allora che la supposizione si insinua. Un workflow leggero e ripetibile aiuta a passare da “qualcosa è lento” a “sappiamo cosa è cambiato” senza troppa confusione.
Rileva: allerta su latenza ed errori visibili all'utente, non solo su CPU. Avvisa quando p95/p99 supera una soglia per un intervallo sostenuto.
Triage: rispondi subito a tre domande: cosa è lento, quando è cominciato e chi è impattato? Se non riesci a nominare l'ambito (servizio, endpoint, regione, coorte), non sei pronto per ottimizzare.
Misura: raccogli evidenze che restringano il collo di bottiglia. Preferisci catture a tempo (es. 60–180 secondi) per poter confrontare “male” vs “bene”.
Correggi: cambia una cosa per volta, poi misura gli stessi segnali per confermare il miglioramento e scartare l'effetto placebo.
Mantieni una dashboard condivisa che tutti usano durante gli incidenti. Rendila noiosa e coerente:
L'obiettivo non è disegnare tutto; è accorciare il tempo per ottenere il primo fatto.
Instrumenta gli endpoint che contano davvero (checkout, login, search), non ogni singolo endpoint. Per ciascuno, concorda: p95 atteso, tasso massimo di errori e dipendenza chiave (DB, cache, terze parti).
Prima del prossimo outage, concorda un kit di cattura:
Documentalo in un runbook breve (es., /runbooks/latency), includendo chi può attivare le catture e dove conservare gli artifact.
La metodologia di Gregg è fondamentalmente su cambi controllati e verifica rapida. Se il tuo team costruisce servizi con Koder.ai (una piattaforma chat-driven per generare e iterare app web, backend e mobile), due feature si allineano bene con questa mentalità:
Anche se non stai generando nuovo codice durante un incidente, quelle abitudini — diff piccoli, risultati misurabili e rapida reversibilità — sono le stesse che Gregg promuove.
Sono le 10:15 e la dashboard mostra p99 dell'API che passa da ~120 ms a ~900 ms durante il picco. Il tasso di errore è stabile, ma i clienti segnalano richieste “lente”.
Inizia servizio-centrico: Rate, Errors, Duration.
Fetta la Duration per endpoint e vedi che una route domina il p99: POST /checkout. Il rate è salito di 2×, gli errori sono normali, ma la Duration sale specificamente quando aumenta la concurrency. Questo punta a code o contesa, non a un fallimento totale.
Controlla se la latenza è tempo di calcolo o di attesa: confronta il “handler time” dell'app vs il tempo totale (o span upstream vs downstream se hai tracing). L'handler è basso, il tempo totale è alto — le richieste stanno aspettando.
Fai l'inventario delle probabili risorse: Utilization, Saturation, Errors per CPU, memoria, disco e rete.
La CPU è solo ~35%, ma la run queue e i context switch aumentano. Disco e rete sembrano stabili. Questo mismatch (bassa CPU%, alta attesa) è un indizio classico: i thread non stanno consumando CPU — sono bloccati.
Catturi un profilo off-CPU durante il picco e trovi molto tempo speso in un mutex attorno a una cache condivisa di “promotion validation”.
Sostituisci il lock globale con un lock per chiave (o un percorso di lettura lock-free), deploy e osservi il p99 tornare ai livelli normali mentre il Rate resta alto.
Checklist post-incident: