Ogni squadra di ingegneria monitora la produzione. Poche sanno rispondere alla domanda «perché il sistema si comporta così?» senza una lunga sessione di indagine. La differenza fra monitoraggio e osservabilità non è una scelta di strumenti: è una filosofia di progetto che determina quanto in fretta la squadra capisce e affronta guasti che nessuno aveva previsto.
Il monitoraggio tradizionale presuppone che sappiate cosa guardare. Fissate soglie di CPU, controllate i codici di stato e svegliate qualcuno quando il disco supera il 90%. Per i guasti noti funziona. Ma i sistemi distribuiti moderni si rompono in modi che nessun cruscotto aveva anticipato: un lieve peggioramento di latenza in un servizio ingorga una coda, che si manifesta come esaurimento del pool di connessioni alla base di dati e affiora solo nelle ore di punta. Senza la possibilità di porre domande libere sullo stato interno, volate alla cieca.
Perché l'osservabilità va oltre il monitoraggio di base
L'osservabilità è la proprietà di un sistema che permette di dedurne lo stato interno dalle uscite esterne. Il monitoraggio vi dice che qualcosa non va; l'osservabilità vi lascia scoprire cosa è andato storto, anche per un guasto che non avevate mai immaginato. La distinzione è cruciale: il monitoraggio è guidato dagli allarmi e legato ai cruscotti; l'osservabilità è guidata dalle domande ed è ricca di dati.
Quando il sistema emette dati strutturati ad alta cardinalità fra registri, metriche e tracce, potete correlare eventi, scendere fino a singoli utenti o richieste e scoprire la causa di incidenti che nessun allarme a soglia avrebbe mai colto. Le squadre che investono in osservabilità riducono di un ordine di grandezza il tempo medio di risoluzione, perché tirano meno a indovinare e agiscono di più sulle prove.
«Il monitoraggio vi dice se un sistema funziona. L'osservabilità vi lascia chiedere perché non funziona. La seconda è il presupposto per far funzionare sistemi che non si comprendono del tutto, cioè tutti i sistemi in produzione.»
I tre pilastri: registri, metriche e tracce
L'ecosistema dell'osservabilità poggia su tre tipi di dati complementari, ciascuno con uno scopo distinto. Trattarli come un segnale unitario anziché come compartimenti separati è la chiave di un'indagine efficace.
Registri: testimonianze immutabili di eventi
I registri sono annotazioni datate di eventi discreti. Sono il segnale più fine: catturano esattamente cosa è accaduto in un preciso istante. Una riga ben strutturata porta abbastanza contesto — identificativo della richiesta, nome del servizio, durata, dettaglio dell'errore — da ricostruire il percorso di esecuzione senza incrociare più fonti.
L'errore più comune è trattare i registri come testo non strutturato. Frugare in file piatti funzionava con tre server; su larga scala, i registri non strutturati sono rumore. Ogni riga deve essere analizzabile, portare metadati strutturati e seguire uno schema coerente in tutti i servizi dell'architettura.
Metriche: misure aggregate nel tempo
Le metriche sono rappresentazioni numeriche dello stato del sistema, rilevate a intervalli. Sono pensate per una memorizzazione economica e un'aggregazione rapida. Rispondono a «quante richieste al secondo?» o «qual è la latenza al 99º percentile?». A differenza dei registri, scartano il dato della singola richiesta: barattano finezza con compressione e velocità.
I tipi consueti — contatori, indicatori, istogrammi e riepiloghi — servono a scopi diversi. I contatori seguono valori cumulativi, come il totale delle richieste. Gli indicatori registrano valori istantanei, come l'uso di memoria. Gli istogrammi distribuiscono le osservazioni in classi configurabili, per esempio per le distribuzioni di latenza. Scegliere il tipo giusto evita aggregazioni fuorvianti e cardinalità sprecata.
Tracce: il ciclo di vita completo di una richiesta
Le tracce distribuite seguono una singola richiesta mentre attraversa i confini fra servizi. Ogni traccia si compone di segmenti: operazioni con un nome e con marche temporali di inizio e fine, che catturano il lavoro svolto da un servizio o da una funzione. Le tracce sono l'unico segnale capace di ricostruire il ciclo di vita completo di una richiesta in un'architettura a microservizi.
Senza tracce, una pagina lenta potrebbe essere attribuita a uno qualsiasi delle decine di servizi coinvolti. Con le tracce individuate che il collo di bottiglia è l'interrogazione alla base di dati del servizio utenti, che impiega 800 millisecondi, mentre ogni altro segmento si chiude sotto i 50. Questa precisione è irraggiungibile con registri o metriche soltanto.
«I registri dicono cosa è successo. Le metriche, quante volte è successo. Le tracce, come tutto si incastra. Servono tutte e tre per attraversare un incidente di produzione senza fare supposizioni.»
Configurazione e strumentazione con OpenTelemetry
OpenTelemetry è lo standard del settore per produrre, raccogliere ed esportare dati di telemetria. Offre, da un linguaggio all'altro, un unico insieme di API e kit che emettono registri, metriche e tracce in un formato neutro rispetto al fornitore. Adottarlo elimina il vincolo a un solo produttore e assicura che la vostra strumentazione funzioni sia con una piattaforma commerciale sia con una catena interna.
Strumentazione automatica e manuale
Quasi tutti i kit offrono strumentazione automatica: agganci senza codice a librerie e framework diffusi. Una sola chiamata di inizializzazione può strumentare server HTTP, client di base di dati, code di messaggi e chiamate gRPC. L'automatismo copre i percorsi consueti; per il codice critico per il business, i middleware propri e le operazioni di dominio serve la strumentazione manuale.
import { NodeSDK } from "@opentelemetry/sdk-node";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-grpc";
import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-grpc";
import { HttpInstrumentation } from "@opentelemetry/instrumentation-http";
import { ExpressInstrumentation } from "@opentelemetry/instrumentation-express";
import { PgInstrumentation } from "@opentelemetry/instrumentation-pg";
import { Resource } from "@opentelemetry/resources";
import { SEMRESATTRS_SERVICE_NAME } from "@opentelemetry/semantic-conventions";
const sdk = new NodeSDK({
resource: new Resource({
[SEMRESATTRS_SERVICE_NAME]: "payment-service",
}),
traceExporter: new OTLPTraceExporter({
url: "http://otel-collector:4317",
}),
metricExporter: new OTLPMetricExporter({
url: "http://otel-collector:4317",
}),
instrumentations: [
new HttpInstrumentation(),
new ExpressInstrumentation(),
new PgInstrumentation(),
],
});
sdk.start();
process.on("SIGTERM", () => sdk.shutdown());L'architettura del collettore OpenTelemetry
Il collettore OpenTelemetry è un intermediario neutro che riceve, elabora ed esporta telemetria. È l'ossatura di qualsiasi catena di osservabilità in produzione. Distribuire un collettore per host, o come gruppo nella vostra infrastruttura Kubernetes, separa la strumentazione dalla scelta della destinazione e permette di raggruppare, filtrare, campionare e trasformare i dati prima che raggiungano la piattaforma.
I collettori possono ospitare processori di campionamento a coda: conservano tracce complete per le richieste lente o in errore e scartano gran parte del traffico sano. Il costo di memorizzazione cala nettamente senza sacrificare la capacità di indagare proprio sulle richieste che contano.
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
batch:
timeout: 1s
send_batch_size: 1024
memory_limiter:
check_interval: 1s
limit_mib: 512
filter:
error_mode: ignore
traces:
span:
- 'attributes["http.target"] == "/healthz"'
- 'attributes["http.target"] == "/metrics"'
attributes:
actions:
- key: environment
value: production
action: upsert
exporters:
otlp:
endpoint: "collector.example.com:443"
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, filter, batch, attributes]
exporters: [otlp]
metrics:
receivers: [otlp]
processors: [memory_limiter, batch, attributes]
exporters: [otlp]
logs:
receivers: [otlp]
processors: [memory_limiter, batch, attributes]
exporters: [otlp]Schemi di registrazione strutturata
Registrare in modo strutturato significa emettere voci in un formato leggibile dalla macchina — di solito JSON — con nomi di campo coerenti fra i servizi. I registri smettono di essere un problema di ricerca e diventano un problema di interrogazione. Quando tutte le squadre usano le stesse convenzioni per identificativi di richiesta, nomi di servizio, codici di errore e durate, potete interrogare l'intera infrastruttura senza scrivere analizzatori su misura.
Progettare lo schema dei registri
Ogni evento strutturato dovrebbe includere un minimo di attributi: marca temporale, livello di gravità, nome del servizio, identificativo di traccia, identificativo di segmento e messaggio. Oltre a questi, aggiungete campi di dominio, ma rispettate le convenzioni di nome. Usate per esempio sempre la stessa grafia, anteponete un prefisso comune ai campi dell'utente e riponete il dettaglio dell'errore in un oggetto annidato invece di concatenarlo al messaggio.
- Includete sempre trace_id e span_id per correlare registri e tracce
- Usate un livello (debug, info, warn, error) che corrisponda a segnali su cui si può agire, non alla comodità di chi scrive il codice
- Non registrate mai dati sensibili — dati personali, segreti o gettoni —, nemmeno in sviluppo
- Tenete i messaggi fissi e mettete i dati variabili in campi strutturati, così da poter aggregare
- Uniformate il formato della marca temporale su tutti i servizi: RFC 3339 o millisecondi Unix
Trappole frequenti
L'errore più costoso è registrare troppo. Campi ad alta cardinalità, come identificativi utente o indirizzi IP, possono gonfiare il volume di ordini di grandezza. Campionate i registri di diagnostica più voluminosi e riservate il dettaglio a determinate tracce o a condizioni di errore. Il secondo errore è l'incoerenza dei nomi: un servizio con user_id, un altro con customerId e un terzo con user.id rendono impossibili le interrogazioni trasversali senza strati di trasformazione.
«Una riga di registro che non si può interrogare tanto varrebbe non esistesse. La registrazione strutturata non riguarda la leggibilità: riguarda il rendere ogni voce una cittadina di prima classe della vostra piattaforma di osservabilità.»
Tracce distribuite nei microservizi
Le tracce distribuite sono lo strumento più efficace per indagare su un'architettura a microservizi. Una traccia che attraversa venti servizi dice esattamente dove si consuma il tempo, quali richieste falliscono e come si propagano gli errori. Senza tracce, indagare su un percorso d'acquisto lento significa esaminare i registri di una dozzina di servizi e tirare a indovinare sulla causalità.
Propagazione del contesto di traccia
Il contesto di traccia va propagato a ogni confine fra servizi: intestazioni HTTP, metadati delle code di messaggi, metadati gRPC e perfino attraverso confini asincroni come lavori pianificati o processi in secondo piano. OpenTelemetry se ne occupa da sé se usate le sue librerie per HTTP, gRPC e messaggistica. L'identificativo di traccia scorre dal varco d'ingresso lungo ogni servizio a valle, raccogliendo segmenti strada facendo.
- Strumentate tutti i punti d'ingresso: gateway di API, bilanciatori di carico, controllori d'ingresso
- Propagate il contesto attraverso le code di messaggi con intestazioni o metadati del messaggio
- Includete l'identificativo di traccia nell'uscita dei registri, per poter correlare registro e traccia
- Adottate un campionamento che preservi le tracce con errori o latenza alta
- Aggiungete attributi propri ai segmenti per il contesto di business: livello del cliente, codice prodotto, regione
Leggere e interpretare una traccia
Una traccia ben annotata rivela il percorso critico di una richiesta. Concentratevi sul segmento di durata maggiore: è il vostro collo di bottiglia. Cercate segmenti con eventi di errore o con attributi molto vari. Confrontate tracce di richieste riuscite e fallite per riconoscere schemi. Se le tracce mostrano sistematicamente una chiamata a valle che va in timeout, avete un problema di dipendenza, non un difetto applicativo.
Allerte: su cosa avvisare e come evitare la stanchezza
La stanchezza da allerte è la minaccia maggiore alla gestione degli incidenti. Quando una squadra riceve cinquanta avvisi per turno, li ignora tutti. Lo scopo di una buona strategia non è rilevare ogni anomalia, ma produrre un insieme piccolo e ad alto segnale di notifiche che richiedano giudizio umano. Tutto il resto appartiene a un cruscotto o a un'interrogazione.
Il sistema a livelli
Organizzate le allerte in tre livelli. Il livello 1 sveglia subito chi è reperibile, perché segnala un problema visibile all'utente: tasso di errore alto, servizio del tutto irraggiungibile, o consumo del budget di errore oltre soglia. Il livello 2 apre un ticket da smistare il giorno lavorativo successivo: latenza elevata, componenti degradati ma non caduti. Il livello 3 è informativo: certificato in scadenza, limiti di archiviazione vicini.
- Avvisate solo sui sintomi, non sulle cause. L'utente vede un errore 5xx: allertate su quello, non sull'uso della CPU
- Usate condizioni multiple che richiedano una deviazione prolungata prima di scattare (per esempio cinque minuti oltre soglia)
- Fissate un massimo di tre avvisi con chiamata per persona e per turno, così da mantenere la qualità del segnale
- Rivedete e sfoltite le regole ogni trimestre: le allerte obsolete erodono la fiducia nel sistema
- Allegate a ogni allerta il collegamento a una guida operativa, così chi risponde conosce i primi tre passi
Allerte sul ritmo di consumo
Queste allerte scattano quando il budget di errore si consuma più in fretta del previsto. A differenza delle soglie fisse, sono legate direttamente agli obiettivi di servizio. Con un obiettivo del 99,9% di disponibilità su 30 giorni, avete circa 43 minuti di disservizio. L'allerta scatta quando il consumo proiettato esaurirebbe la finestra prima del previsto, lasciandovi il tempo di reagire prima che l'obiettivo sia mancato.
Costruire cruscotti utili
Gran parte dei cruscotti è un cimitero di grafici inutilizzati. Un cruscotto è utile quando risponde a una domanda precisa senza richiedere interpretazione. I migliori sono costruiti per un solo profilo e un solo uso: un cruscotto di reperibilità per smistare gli incidenti, uno settimanale per la pianificazione della capacità e uno di squadra per seguire il raggiungimento degli obiettivi.
Il cruscotto di reperibilità
Deve stare in una schermata e rispondere a quattro domande: il servizio è in piedi? qual è il tasso di errore? come si distribuisce la latenza? il budget di errore è stato superato? Ogni grafico deve avere una linea di soglia chiara, così si vede subito se il valore attuale è sano. Non mettete più di sei grafici: durante un incidente il carico mentale conta.
- Partite dalle metriche RED: ritmo (richieste al secondo), errori (richieste fallite), durata (percentili di latenza)
- Aggiungete le metriche USE per l'infrastruttura: utilizzo, saturazione ed errori per risorsa
- Mostrate il raggiungimento dell'obiettivo e il ritmo di consumo come indicatori ben visibili
- Collegate ogni grafico ai suoi registri o alla sua interrogazione di tracce, per scendere nel dettaglio con un clic
- Usate scale logaritmiche per la latenza: quelle lineari nascondono variazioni importanti nelle code
Anti-schemi comuni
L'anti-schema più diffuso è il cruscotto che mostra ogni metrica prodotta dall'infrastruttura. Questi «muri di verde» danno un falso senso di sicurezza e rendono impossibile trovare il segnale durante un incidente. Altri difetti: grafici a torta per serie temporali, più metriche impilate su assi incoerenti, linee di soglia senza etichetta. Se un grafico ha bisogno di un commento per essere capito, non appartiene al cruscotto.
SLI, SLO e budget di errore
Indicatori, obiettivi e budget di errore formano il contratto fra la vostra squadra e i vostri utenti. Gli indicatori sono le misure grezze: latenza, tasso di errore, portata. Gli obiettivi sono gli impegni che assumete: il 99,9% delle richieste sotto i 200 millisecondi. Il budget di errore è il margine di fallimento ammesso — quello 0,1% che dà alla squadra il permesso di rilasciare, sperimentare e iterare senza temere di venir meno agli impegni.
Scegliere indicatori sensati
Un buon indicatore guarda all'utente, si misura e conduce all'azione. Disponibilità (quota di richieste riuscite), latenza (quota sotto una soglia) e freschezza (età dei dati serviti) sono i più comuni per un servizio web. La chiave è misurare dal punto di vista dell'utente: una richiesta che il vostro server risolve in 50 millisecondi ma che su una rete mobile lenta impiega due secondi, per chi l'ha fatta è un fallimento.
Fissare obiettivi realistici
Un obiettivo del 99,999% suona impressionante ma ha un costo ingegneristico enorme. Ogni nove in più richiede circa dieci volte più investimento in ridondanza, prove e strumenti operativi. Partite dal 99,9% per la maggior parte dei servizi e riservate obiettivi più alti ai percorsi critici verso il cliente. Siate onesti su ciò che potete reggere: un obiettivo costantemente mancato è peggio di nessun obiettivo, perché normalizza il fallimento e logora la fiducia nelle misure.
Come il budget di errore dà velocità
Il budget di errore trasforma l'affidabilità da vincolo in rischio misurabile. Quando è pieno, la squadra rilascia con libertà, sapendo di avere margine. Quando è esaurito, sospende i rilasci non critici e si dedica soltanto all'affidabilità. Nasce così un processo decisionale chiaro e fondato sui dati, che sostituisce le discussioni soggettive sul fatto che un rilascio sia «abbastanza sicuro».
Osservabilità in ambienti serverless e di bordo
Serverless e calcolo di bordo pongono difficoltà proprie. Le funzioni sono effimere, l'infrastruttura è astratta e l'esecuzione si distribuisce su punti di presenza sparsi nel mondo. Il monitoraggio classico con agenti non regge, perché non c'è un host su cui farli girare. Qui serve un altro approccio: telemetria spinta dal codice, tracce fini per gli avvii a freddo e una gestione attenta della cardinalità su distribuzioni globali.
Schemi propri del serverless
L'avvio a freddo domina la latenza. Strumentate l'inizializzazione separatamente dalla gestione della richiesta, così da distinguere la latenza di avvio da quella della logica di dominio. Usate la registrazione strutturata per catturare il contesto dell'invocazione — identificativo della richiesta, regione, versione della funzione, ambiente di esecuzione — ed emettete metriche proprie di numero di invocazioni, durata e tasso di errore in modo asincrono, per non bloccare la risposta.
- Misurate la durata dell'avvio a freddo come metrica propria: nelle metriche standard del fornitore è invisibile
- Usate propagatori OpenTelemetry compatibili con il meccanismo di estensione della vostra piattaforma
- Esportate la telemetria a lotti, per non allungare il tempo di esecuzione della funzione
- Impostate metriche derivate dai registri dove non esiste un'API per metriche proprie
- Etichettate tutta la telemetria con ambiente, regione e versione della funzione, così da filtrare con efficacia
Particolarità del bordo
Le piattaforme di bordo eseguono codice in decine di luoghi sparsi nel mondo. Questa dispersione rende impraticabile la raccolta centralizzata classica. Usate strumenti pensati per il bordo, che raccolgano telemetria in ogni punto e la aggreghino centralmente con poco peso. Sorvegliate il tasso di errore per regione: un problema di rete locale può degradare il servizio in una zona mentre la media mondiale sembra sana.
Costruire una cultura dell'osservabilità
Strumenti e catene di elaborazione sono necessari ma non bastano. La parte più difficile dell'osservabilità è culturale. La squadra deve tenere il codice strumentato in considerazione quanto il codice provato. Ogni nuova funzionalità dovrebbe includere la strumentazione nella propria definizione di «fatto», esattamente come include prove unitarie e revisione. Questo richiede infrastruttura: librerie condivise, convenzioni documentate e in ogni squadra qualcuno che porti avanti il tema.
Rendere l'osservabilità una questione di primo piano
Iniziate scrivendo un documento di progetto della telemetria, che definisca i campi standard, le convenzioni di nome delle metriche e i requisiti di tracciamento per ogni servizio. Rendetelo parte dell'avvio di ogni nuovo servizio. Predisponete nell'integrazione continua controlli automatici che impongano una strumentazione minima: rifiutate, per esempio, le richieste di merge che aggiungono gestori HTTP senza il corrispondente tracciamento o le voci di registro strutturate.
- Inserite la strumentazione nella definizione di «fatto» di ogni funzionalità
- Organizzate regolarmente giornate di esercitazione in cui la squadra indaga usando solo cruscotti e interrogazioni di tracce
- Celebrate i successi: condividete analisi di incidenti che mostrino come una buona telemetria abbia portato a una risoluzione rapida
- Assegnate referenti a rotazione che a ogni iterazione controllino la qualità della telemetria fra le squadre
- Investite in librerie di strumentazione condivise, che rendano la cosa giusta più facile di quella sbagliata
Il circuito di ritorno
L'osservabilità non è un'installazione una tantum, è un circuito continuo: strumentare, rilasciare, osservare, imparare, migliorare. Quando un incidente rivela un punto cieco — una metrica non seguita, un campo di registro mancante, una traccia scartata — trattatelo come un difetto della vostra piattaforma di osservabilità e correggetelo. Con il tempo la telemetria si completa, l'indagine si accelera e la squadra acquista la sicurezza di poter comprendere qualunque guasto, anche uno mai visto prima.
«Lo scopo dell'osservabilità non è impedire gli incidenti. È fare in modo che, quando accadono, la squadra abbia i dati, gli strumenti e la sicurezza per risolverli prima che gli utenti se ne accorgano.»
Adottare l'osservabilità è un percorso, non un acquisto. Cominciate in piccolo: strumentate da capo a fondo un servizio critico, costruite un solo cruscotto utile e scrivete un obiettivo di servizio che abbia senso. Lasciate che il valore parli da sé. Una volta che la squadra avrà sperimentato, in pieno incidente, la differenza fra indovinare e sapere, non vorrà più tornare indietro.