Executive summary
Quando un sistema software è composto da decine o centinaia di componenti che comunicano tra loro attraverso la rete, individuare la causa di un rallentamento o di un malfunzionamento diventa un problema di complessità crescente. Questo articolo analizza le tecniche e gli standard più maturi per rendere trasparente il comportamento interno di tali sistemi, raccogliendo e correlando tre tipi fondamentali di dati operativi: registri di eventi, misurazioni quantitative e tracciamenti delle richieste lungo l'intera catena di servizi. L'analisi mostra che l'adozione di uno standard aperto per la raccolta di questi dati, unita a obiettivi di affidabilità misurabili e a strategie di notifica calibrate sull'impatto reale sugli utenti, riduce significativamente i tempi di diagnosi e migliora la stabilità complessiva del servizio. Le organizzazioni che trattano l'osservabilità come disciplina ingegneristica, e non come semplice raccolta di dati, ottengono un vantaggio concreto nella gestione di architetture distribuite complesse.
Background
Il concetto di osservabilità ha radici nella teoria dei sistemi di controllo, dove indica la capacità di inferire lo stato interno di un sistema a partire dalle sue uscite osservabili. Nel contesto dell'ingegneria del software, il termine ha acquisito un significato operativo distinto a partire dalla seconda metà degli anni 2010, quando la migrazione verso architetture a microservizi ha reso inadeguati gli approcci tradizionali di monitoring basati su soglie statiche e dashboard predefinite [1]. La distinzione tra monitoring e observability è sostanziale: il monitoring verifica condizioni note a priori ("il tempo di risposta supera i 500 ms?"), mentre l'observability consente di formulare domande arbitrarie su un sistema in produzione senza dover predefinire quali dati raccogliere [2].
Questa transizione è stata accelerata da due fattori convergenti. Da un lato, la diffusione di container orchestration e service mesh ha moltiplicato il numero di componenti indipendenti, rendendo la correlazione tra eventi un problema combinatorio. Dall'altro, la disciplina della Site Reliability Engineering (SRE), formalizzata da Google nel 2016, ha introdotto un framework operativo che lega esplicitamente la telemetria a obiettivi di affidabilità quantificabili [3]. Il capitolo dedicato al monitoring dei sistemi distribuiti nel volume originale SRE stabilisce un principio fondamentale: ogni alert deve essere actionable, e ogni dato raccolto deve contribuire a rispondere a una domanda operativa concreta [4].
Il panorama degli strumenti si è evoluto in parallelo. Prometheus, graduato dalla Cloud Native Computing Foundation (CNCF) nel 2018 come secondo progetto dopo Kubernetes, ha consolidato il modello pull-based per la raccolta di metriche time-series con un linguaggio di query nativo (PromQL) [5]. Jaeger, anch'esso progetto CNCF, ha portato il distributed tracing nell'ecosistema cloud-native, ispirandosi direttamente all'architettura descritta nel paper Dapper di Google [6]. La frammentazione tra questi strumenti, ciascuno con il proprio formato di dati, le proprie API e i propri agent, ha motivato la nascita di OpenTelemetry, il progetto CNCF che mira a unificare la raccolta di tutti i segnali di telemetria sotto un unico standard [7].
I tre pilastri della telemetria
La metafora dei "tre pilastri", log, metriche e trace, è diventata il framework concettuale dominante per classificare i segnali di telemetria nei sistemi distribuiti. Ciascun pilastro cattura una dimensione diversa del comportamento del sistema, e la loro efficacia dipende dalla capacità di correlarli reciprocamente.
Log: eventi discreti con contesto
Un log è un record immutabile di un evento discreto, tipicamente associato a un timestamp e a un insieme di attributi strutturati o semi-strutturati. Nei sistemi distribuiti, i log rappresentano la fonte di informazione più granulare: ogni componente produce log che documentano decisioni interne, errori, cambiamenti di stato e interazioni con altri servizi. La sfida principale non è la generazione dei log, che è pressoché universale, ma la loro aggregazione, indicizzazione e interrogazione a scala. Stack come ELK (Elasticsearch, Logstash, Kibana) e Grafana Loki hanno affrontato questo problema con approcci architetturali distinti: indicizzazione full-text nel primo caso, indicizzazione dei soli metadati con compressione dei contenuti nel secondo [1].
Il passaggio dai log non strutturati (testo libero) ai log strutturati (coppie chiave-valore o JSON) ha rappresentato un'evoluzione critica. I log strutturati consentono query analitiche senza parsing regex, abilitano la correlazione automatica con trace e metriche attraverso campi condivisi come trace_id e span_id, e riducono il costo di storage grazie alla compressione colonnare. OpenTelemetry definisce un modello di log che include severità, corpo del messaggio, attributi di risorsa e contesto di trace, fornendo un formato unificato indipendente dal backend di destinazione [7].
Un problema aperto riguarda il volume: in sistemi ad alto throughput, la generazione di log per ogni richiesta diventa proibitiva in termini di costo di storage e di banda. Le strategie di campionamento, head-based (decisione al punto di ingresso) e tail-based (decisione dopo il completamento della trace), riducono il volume ma introducono il rischio di perdere eventi diagnostici rilevanti. La letteratura recente evidenzia che il campionamento tail-based, pur più complesso da implementare, offre un compromesso migliore perché consente di conservare selettivamente le trace anomale o con errori [2, 8].
Metriche: misurazioni aggregate nel tempo
Le metriche sono misurazioni numeriche aggregate su intervalli temporali regolari, rappresentate come serie temporali. A differenza dei log, che catturano eventi individuali, le metriche sintetizzano il comportamento del sistema in indicatori statistici: contatori (valori monotonicamente crescenti), gauge (valori istantanei), istogrammi (distribuzioni di valori) e summary (percentili pre-calcolati). Prometheus ha standardizzato questa tassonomia nel contesto cloud-native, introducendo un modello di dati multidimensionale in cui ogni serie temporale è identificata da un nome e da un insieme di label chiave-valore [5].
Il framework dei four golden signals proposto nel Google SRE Book identifica quattro metriche fondamentali per il monitoring di qualsiasi servizio user-facing: latency (tempo di risposta delle richieste), traffic (volume di richieste al sistema), errors (tasso di richieste fallite) e saturation (grado di utilizzo delle risorse) [4]. Questo framework ha il merito di focalizzare l'attenzione sulle metriche che correlano direttamente con l'esperienza utente, evitando la proliferazione di indicatori infrastrutturali a bassa rilevanza operativa. Un approccio complementare è il metodo USE (Utilization, Saturation, Errors) proposto da Brendan Gregg, orientato alla diagnosi di problemi a livello di risorse fisiche, CPU, memoria, I/O, rete, piuttosto che di servizi applicativi [9].
La cardinalità rappresenta la sfida architetturale principale per i sistemi di metriche. Ogni combinazione unica di label produce una serie temporale distinta, e label ad alta cardinalità (come user_id o request_id) possono generare milioni di serie temporali, degradando le prestazioni di ingestione e query. Le soluzioni moderne adottano strategie di pre-aggregazione, downsampling temporale e limiti di cardinalità espliciti, ma il trade-off tra granularità e costo resta un problema progettuale non banale [5, 8].
Trace: il percorso di una richiesta attraverso il sistema
Una trace rappresenta il percorso end-to-end di una singola richiesta attraverso un sistema distribuito, modellato come un grafo aciclico diretto (DAG) di span. Ogni span corrisponde a un'unità di lavoro, una chiamata RPC, una query a database, un'elaborazione asincrona, e registra timestamp di inizio e fine, attributi, eventi e relazioni parent-child con altri span. La trace ricostruisce la topologia causale della richiesta, rendendo visibili latenze, dipendenze e punti di fallimento che sarebbero invisibili analizzando log o metriche in isolamento [6].
Il paper fondativo di questo approccio è Dapper, a Large-Scale Distributed Systems Tracing Infrastructure, pubblicato da Sigelman et al. presso Google nel 2010 [6]. Dapper ha introdotto i principi progettuali che guidano ancora oggi i sistemi di tracing: basso overhead di runtime (campionamento adattivo per limitare l'impatto sulle prestazioni), trasparenza applicativa (instrumentazione iniettata a livello di librerie di comunicazione, senza modifiche al codice applicativo) e identificatori probabilisticamente unici a 64 bit per trace e span. L'architettura Dapper ha ispirato direttamente Zipkin (Twitter, 2012) e Jaeger (Uber, 2017), entrambi successivamente donati alla comunità open-source.
La propagazione del contesto di trace tra servizi richiede un meccanismo standardizzato di trasporto degli identificatori. La specifica W3C Trace Context, divenuta Recommendation nel 2020 e aggiornata con il Level 2 nel 2024, definisce due header HTTP, traceparent e tracestate, che consentono la propagazione interoperabile del contesto di trace attraverso servizi instrumentati con strumenti diversi [10]. OpenTelemetry adotta W3C Trace Context come formato di propagazione predefinito, eliminando una delle principali barriere all'interoperabilità nell'ecosistema del distributed tracing [7].
Correlazione tra pilastri
L'efficacia dell'observability non risiede nei singoli pilastri ma nella capacità di correlarli. Un alert generato da una metrica (ad esempio, un aumento del tasso di errori 5xx) deve poter condurre a una trace specifica che mostra quale servizio downstream ha fallito, e da quella trace ai log dettagliati che spiegano la causa dell'errore. Questa correlazione richiede un contesto condiviso: il trace_id deve essere presente nei log, nelle metriche esemplari e negli span. OpenTelemetry abilita questa correlazione natively, iniettando automaticamente il contesto di trace in tutti i segnali di telemetria emessi dallo stesso SDK [7, 2].
graph LR
A[Richiesta utente] --> B[Servizio A]
B --> C[Servizio B]
B --> D[Servizio C]
C --> E[Database]
D --> F[Cache]
subgraph Telemetria correlata
G[Metriche: latency p99 = 450ms]
H[Trace: span tree con 5 span]
I[Log: error in Servizio B, trace_id=abc123]
end
B -.-> G
B -.-> H
C -.-> I
Figura 1. Correlazione tra i tre pilastri di telemetria per una singola richiesta distribuita. Il trace_id condiviso consente la navigazione tra metriche, trace e log.
OpenTelemetry: verso uno standard unificato
OpenTelemetry (OTel) è il progetto CNCF nato nel 2019 dalla fusione di OpenTracing e OpenCensus, con l'obiettivo di fornire un unico set di API, SDK e strumenti per la generazione, raccolta e trasmissione di dati di telemetria vendor-neutral [7]. Il progetto ha raggiunto lo status di graduated project CNCF, e rappresenta il secondo progetto per numero di contributori nell'ecosistema CNCF dopo Kubernetes.
Architettura e componenti
L'architettura di OpenTelemetry si articola su tre livelli. Il primo livello è costituito dalle API, che definiscono le interfacce per la creazione di span, metriche e log record senza dipendenze da implementazioni specifiche. Il secondo livello comprende gli SDK, implementazioni di riferimento delle API disponibili per tutti i principali linguaggi (Java, Python, Go, .NET, JavaScript, Rust, tra gli altri), che gestiscono campionamento, batching, e export dei dati. Il terzo livello è il Collector, un componente infrastrutturale che riceve, elabora e inoltra telemetria verso uno o più backend [7].
Il Collector merita un'analisi dettagliata per il suo ruolo architetturale. Operando come un pipeline configurabile, il Collector implementa tre categorie di componenti: receiver (accettano dati in ingresso in formati diversi, inclusi OTLP, Jaeger, Zipkin e Prometheus), processor (trasformano, filtrano, campionano o arricchiscono i dati in transito) e exporter (inviano i dati elaborati verso backend di destinazione). Questa architettura disaccoppia l'instrumentazione applicativa dal backend di observability, consentendo di cambiare vendor senza modificare il codice sorgente, un vantaggio strategico che riduce il lock-in tecnologico [7, 8].
OTLP: il protocollo di trasporto
L'OpenTelemetry Protocol (OTLP) è il protocollo wire nativo del progetto, progettato per il trasporto efficiente di tutti i segnali di telemetria su gRPC e HTTP/protobuf. OTLP definisce endpoint dedicati per ciascun segnale (/v1/traces, /v1/metrics, /v1/logs) e supporta compressione gzip, retry con backoff esponenziale e acknowledgment esplicito [11]. A differenza dei protocolli legacy specifici per singolo segnale (come il remote write di Prometheus per le metriche o il formato Thrift di Jaeger per le trace), OTLP offre un formato unificato che semplifica l'infrastruttura di raccolta e riduce la superficie di configurazione.
La specifica OTLP 1.x ha stabilizzato il supporto per trace, metriche e log. Il quarto segnale, il continuous profiling, ha raggiunto lo status di release candidate nel primo trimestre 2026, estendendo il modello di telemetria alla profilazione delle prestazioni a livello di funzione [11]. Questa estensione è significativa perché collega la telemetria di sistema (cosa sta accadendo) con la telemetria di codice (dove il codice sta spendendo tempo), abilitando un ciclo diagnostico completo dalla rilevazione dell'anomalia alla riga di codice responsabile.
Instrumentazione automatica e manuale
OpenTelemetry supporta due modalità di instrumentazione. L'instrumentazione automatica (zero-code) utilizza agent o hook a livello di runtime per intercettare chiamate a librerie note (framework HTTP, client di database, message broker) e generare span e metriche senza intervento dello sviluppatore. L'instrumentazione manuale richiede l'uso esplicito delle API OTel nel codice applicativo per creare span personalizzati, aggiungere attributi di business e registrare eventi. Nella pratica, la maggior parte dei deployment combina entrambe le modalità: l'instrumentazione automatica fornisce la baseline di visibilità, mentre quella manuale arricchisce i punti critici per il business [7].
SLI, SLO e SLA: dalla telemetria agli obiettivi di affidabilità
La telemetria, da sola, produce dati. Per trasformare quei dati in decisioni operative, è necessario un framework che leghi le misurazioni a obiettivi di affidabilità espliciti. La triade SLI/SLO/SLA, formalizzata nel contesto SRE da Google, fornisce questo collegamento [3].
Service Level Indicator (SLI)
Un SLI è una misurazione quantitativa del comportamento di un servizio dal punto di vista dell'utente. La formulazione canonica è un rapporto:
$$SLI = \frac{\text{eventi validi}}{\text{eventi totali}} \times 100\%$$
dove "valido" è definito in base alla dimensione misurata: una richiesta completata entro una soglia di latenza, una richiesta restituita senza errore, un dato disponibile entro un tempo definito. La scelta degli SLI è un atto progettuale critico: SLI mal definiti producono obiettivi che non correlano con l'esperienza utente reale. Il Google SRE Workbook raccomanda di derivare gli SLI da quattro categorie: disponibilità, latenza, qualità e copertura, selezionando per ciascun servizio gli indicatori più rappresentativi del valore percepito dall'utente [12].
Service Level Objective (SLO)
Un SLO è un valore target per un SLI, espresso come percentuale su una finestra temporale definita. Ad esempio: "il 99.9% delle richieste API deve completarsi in meno di 300 ms su una rolling window di 28 giorni". La scelta del target non è arbitraria: deve riflettere il livello di affidabilità effettivamente necessario per il contesto di business, non il massimo tecnicamente raggiungibile [3, 4].
Il concetto di error budget discende direttamente dall'SLO: se il target è 99.9%, il budget di errore è 0.1%, corrispondente a circa 40 minuti di indisponibilità in un periodo di 28 giorni. L'error budget funziona come meccanismo di governance: finché il budget non è esaurito, i team di sviluppo possono rilasciare nuove funzionalità e assumere rischio; quando il budget si esaurisce, le priorità si spostano verso la stabilizzazione [3, 13]. Questo meccanismo è efficace perché trasforma una discussione qualitativa ("il sistema è abbastanza affidabile?") in una decisione quantitativa basata su dati di telemetria.
Un aspetto spesso sottovalutato è l'uso di SLO a percentili multipli. Per un SLI di latenza, definire un singolo SLO sul p50 o sul p99 cattura solo una parte della distribuzione. La pratica raccomandata prevede almeno due target: uno sulla mediana (esperienza tipica) e uno sulla coda (esperienza nel caso peggiore), ad esempio "p50 < 100 ms e p99 < 400 ms" [12]. Questo approccio previene la situazione in cui la latenza mediana è accettabile ma una frazione significativa di utenti sperimenta degradazioni severe.
Service Level Agreement (SLA)
Un SLA è un contratto formale tra fornitore e cliente che definisce le conseguenze del mancato rispetto di un SLO: penali economiche, crediti di servizio, clausole di rescissione. La relazione gerarchica è rigorosa: l'SLA si basa sull'SLO, che si basa sull'SLI. Un errore comune è definire SLA senza SLO misurabili, producendo impegni contrattuali non ancorati a dati operativi. La best practice prevede che gli SLO interni siano più stringenti degli SLA esterni, creando un margine di sicurezza che consente di intervenire prima che la violazione contrattuale si materializzi [3, 4].
Il ciclo SLI-SLO-alerting
La connessione operativa tra SLI/SLO e alerting è il punto in cui la telemetria diventa azione. Il capitolo "Alerting on SLOs" del Google SRE Workbook formalizza diverse strategie per generare alert basati sul consumo dell'error budget piuttosto che su soglie statiche [13]. L'approccio a burn rate calcola la velocità con cui il budget di errore viene consumato: se il tasso di consumo corrente proietterebbe l'esaurimento del budget prima della fine della finestra temporale, viene generato un alert. Questo metodo riduce drasticamente i falsi positivi perché tollerà transitori brevi e reagisce solo a degradazioni sostenute.
Strategie di alerting e gestione degli incidenti
Un sistema di observability che genera dati senza tradurli in azioni operative è un costo, non un investimento. Le strategie di alerting determinano come e quando i dati di telemetria innescano interventi umani, e la loro qualità ha un impatto diretto sull'efficacia operativa dei team e sulla stabilità del servizio.
Il problema dell'alert fatigue
L'alert fatigue, la desensibilizzazione degli operatori causata da un volume eccessivo di notifiche non actionable, è il problema più pervasivo nei sistemi di monitoring mal progettati. Il Google SRE Book è esplicito: "Every time the pager goes off, I should be able to react with a sense of urgency. I can only react with a sense of urgency a few times a day before I become fatigued" [4]. Un alert efficace deve soddisfare tre criteri: deve richiedere un intervento umano (se la risposta è automatizzabile, non dovrebbe essere un alert), deve essere urgente (se può attendere, dovrebbe essere un ticket, non una page), e deve fornire contesto sufficiente per iniziare la diagnosi senza ulteriori ricerche.
La causa principale dell'alert fatigue risiede nell'alerting basato su cause piuttosto che su sintomi. Generare alert per l'utilizzo della CPU al 90%, la memoria al 85% o il disco al 80% produce un volume elevato di notifiche che spesso non correlano con degradazioni percepibili dall'utente. L'approccio symptom-based, proposto da Rob Ewaschuk nel contesto SRE, inverte la logica: si genera l'alert quando l'SLI degrada (sintomo), e si usano le metriche infrastrutturali come strumenti di diagnosi, non come trigger [4, 13].
Strategie di alerting basate su SLO
L'alerting basato su SLO rappresenta l'evoluzione più significativa rispetto all'alerting tradizionale a soglie. Il SRE Workbook descrive tre approcci con complessità e precisione crescenti [13]:
Burn rate a finestra singola. Si calcola il rapporto tra il tasso di errore corrente e il tasso massimo tollerato dall'SLO. Un burn rate di 1 indica che il budget viene consumato esattamente al ritmo previsto; un burn rate di 10 indica un consumo 10 volte superiore, proiettando l'esaurimento del budget in un decimo della finestra. L'alert scatta quando il burn rate supera una soglia definita.
Burn rate multi-window. Si combinano una finestra breve (ad esempio 5 minuti) e una finestra lunga (ad esempio 1 ora) per ridurre i falsi positivi. L'alert scatta solo quando entrambe le finestre indicano un consumo anomalo del budget, filtrando transitori che sarebbero catturati dalla sola finestra breve.
Alerting multi-livello. Si definiscono più livelli di severità in base al burn rate: un burn rate di 14.4 su una finestra di 1 ora (che proietta l'esaurimento del budget in 2% della finestra) genera una page immediata; un burn rate di 1 su una finestra di 3 giorni (che indica un consumo lento ma costante) genera un ticket non urgente. Questo approccio calibra la risposta umana in base all'urgenza effettiva.
Runbook e automazione della risposta
Un alert senza runbook è un alert incompleto. Ogni alert di produzione dovrebbe essere collegato a un documento operativo che descrive: cosa misura l'alert, quale impatto ha sull'utente, quali sono i passi diagnostici immediati e quali azioni correttive sono note. L'automazione progressiva della risposta, dal runbook testuale, al runbook eseguibile, fino alla remediation automatica, riduce il tempo medio di risoluzione (MTTR) e libera gli operatori dalla gestione di incidenti ripetitivi [3, 4]. Le organizzazioni mature adottano un ciclo di miglioramento continuo: ogni incidente alimenta la revisione dei runbook, dei threshold di alerting e dell'instrumentazione.
Distributed tracing in architetture a microservizi
In un'architettura monolitica, il profiling di una richiesta lenta si riduce all'analisi di uno stack trace su un singolo processo. In un'architettura a microservizi, la stessa richiesta può attraversare decine di servizi, ciascuno con il proprio deployment, la propria scala e i propri pattern di fallimento. Il distributed tracing è la tecnica che ricostruisce il percorso causale di una richiesta attraverso questo grafo di servizi.
Anatomia di una trace
Una trace è composta da un insieme di span organizzati in una struttura ad albero (o, più generalmente, un DAG). Lo span radice rappresenta la richiesta iniziale dell'utente; ogni span figlio rappresenta un'operazione downstream causata dallo span padre. Ogni span registra: un identificatore univoco (span_id), l'identificatore della trace (trace_id), il riferimento al parent span, i timestamp di inizio e fine, un insieme di attributi (key-value pairs) e, opzionalmente, eventi (log strutturati associati allo span) e link ad altre trace [6, 7].
Il modello di dati definito da Sigelman et al. in Dapper utilizza identificatori a 64 bit probabilisticamente unici [6]. OpenTelemetry ha esteso questo modello adottando trace_id a 128 bit e span_id a 64 bit, allineandosi alla specifica W3C Trace Context [10]. Questa estensione riduce la probabilità di collisione in sistemi ad altissimo throughput, un problema non trascurabile per piattaforme che elaborano miliardi di richieste al giorno.
Context propagation
La propagazione del contesto è il meccanismo che garantisce la continuità del trace_id attraverso i confini dei servizi. Per le comunicazioni HTTP, la specifica W3C Trace Context definisce l'header traceparent nel formato version-trace_id-parent_id-trace_flags, dove trace_flags include un bit di campionamento che indica se la trace è stata selezionata per la registrazione [10]. Per le comunicazioni basate su message broker (Kafka, RabbitMQ, NATS), il contesto viene propagato attraverso gli header dei messaggi, seguendo convenzioni analoghe.
La propagazione del contesto attraverso confini non standard, chiamate a sistemi legacy, batch processing, code asincrone, resta una sfida implementativa significativa. In questi scenari, il contesto deve essere serializzato esplicitamente e ricostruito all'ingresso del componente downstream, richiedendo instrumentazione manuale e una disciplina progettuale che non tutti i team possiedono [2, 8].
Strategie di campionamento
Il campionamento è necessario perché la registrazione di ogni trace in un sistema ad alto throughput genererebbe volumi di dati insostenibili. Tre strategie principali emergono dalla letteratura e dalla pratica operativa:
Head-based sampling. La decisione di campionamento è presa al punto di ingresso della richiesta, prima che la trace sia completa. È semplice da implementare e a basso overhead, ma presenta un limite strutturale: al momento della decisione non si conosce ancora l'esito della richiesta. Trace con errori o latenze anomale hanno la stessa probabilità di essere scartate delle trace normali [6].
Tail-based sampling. La decisione è posticipata al completamento della trace, quando tutti gli span sono disponibili. Questo consente politiche di campionamento basate su attributi dell'intera trace, errori, latenza elevata, attributi specifici, ma richiede un componente (tipicamente il Collector) che bufferizzi temporaneamente tutte le trace in attesa della decisione. Il costo in memoria e complessità operativa è significativamente superiore [7, 8].
Campionamento adattivo. Il tasso di campionamento viene regolato dinamicamente in base al volume di traffico o a caratteristiche della richiesta. Sotto carico elevato, il tasso diminuisce per proteggere l'infrastruttura di telemetria; per classi di richieste critiche (ad esempio, transazioni finanziarie), il tasso può essere mantenuto al 100%. Dapper implementava una forma di campionamento adattivo che riduceva il tasso fino a 1/1024 sotto carico estremo, mantenendo comunque una rappresentazione statisticamente significativa del comportamento del sistema [6].
Analisi delle trace e root cause analysis
La raccolta delle trace è il prerequisito; il valore emerge dall'analisi. Le tecniche di analisi si dividono in due categorie. L'analisi topologica ricostruisce il grafo delle dipendenze tra servizi a partire dalle trace aggregate, identificando servizi critici (nodi con alto fan-out), colli di bottiglia (span con latenza dominante) e dipendenze fragili (servizi con tasso di errore elevato). L'analisi statistica confronta le distribuzioni di latenza tra trace normali e anomale, identificando gli span la cui latenza devia significativamente dalla baseline. Strumenti come Jaeger e Grafana Tempo offrono interfacce per entrambe le modalità, ma l'analisi automatica della root cause, la capacità di identificare autonomamente la causa di un'anomalia, resta un problema aperto di ricerca [1, 8].
Limiti e problemi aperti
Nonostante la maturità raggiunta dagli strumenti e dagli standard, l'observability nei sistemi distribuiti presenta limitazioni significative che meritano una discussione esplicita.
Costo e scalabilità della telemetria. La raccolta, il trasporto, lo storage e l'interrogazione dei dati di telemetria hanno un costo computazionale e finanziario non trascurabile. In sistemi di grande scala, il volume di telemetria può raggiungere terabyte al giorno, e il costo dell'infrastruttura di observability può rappresentare una frazione significativa del costo totale di esercizio. Le strategie di campionamento, aggregazione e tiering dello storage mitigano il problema ma introducono compromessi sulla completezza dei dati disponibili per la diagnosi [2, 8].
Osservabilità del codice vs. osservabilità del sistema. I tre pilastri tradizionali catturano il comportamento del sistema a livello di richieste e risorse, ma offrono visibilità limitata su cosa accade all'interno di un singolo processo. Il continuous profiling, la raccolta di stack trace a basso overhead in produzione, colma questo gap, e la sua inclusione come quarto segnale in OpenTelemetry rappresenta un riconoscimento formale di questa lacuna [11]. Tuttavia, l'integrazione tra profiling e tracing è ancora in fase di standardizzazione.
Root cause analysis automatica. La correlazione tra segnali di telemetria è oggi largamente manuale: un operatore esperto naviga tra dashboard, trace e log per formulare ipotesi e verificarle. L'applicazione di tecniche di machine learning per l'anomaly detection e la root cause analysis automatica è un'area di ricerca attiva, ma i risultati in produzione sono ancora limitati dalla complessità dei sistemi reali, dalla rarità degli eventi anomali e dalla difficoltà di ottenere ground truth etichettati [1, 8].
Observability delle architetture serverless e edge. Le architetture serverless (FaaS) e edge computing introducono sfide specifiche: funzioni con lifecycle di millisecondi, cold start che distorcono le metriche di latenza, assenza di un processo long-running su cui ancorare l'instrumentazione. L'instrumentazione automatica di OpenTelemetry è meno efficace in questi contesti, richiedendo approcci ibridi che combinano instrumentazione a livello di piattaforma con instrumentazione applicativa leggera [2, 7].
Standardizzazione incompleta. Nonostante i progressi di OpenTelemetry, l'ecosistema resta frammentato in aree specifiche. La semantic convention, l'insieme di nomi standardizzati per attributi di span, metriche e log, è stabile per HTTP, gRPC e database, ma meno matura per messaging, FaaS e infrastruttura cloud-specifica. Questa incompletezza limita l'interoperabilità tra strumenti e la portabilità delle query analitiche tra backend diversi [7, 11].
Riferimenti
[1] M. Narkhede et al., "Observability in Microservices: Metrics, Traces, and Logs for DevOps-Driven Quality Assurance," Journal of Computational Analysis and Applications, 2024. https://www.researchgate.net/publication/393985520
[2] C. Majors, L. Fong-Jones, G. Miranda, Observability Engineering: Achieving Production Excellence, O'Reilly Media, 2022.
[3] B. Beyer, C. Jones, J. Petoff, N. R. Murphy, Site Reliability Engineering: How Google Runs Production Systems, O'Reilly Media, 2016. https://sre.google/sre-book/table-of-contents/
[4] B. Beyer et al., "Monitoring Distributed Systems," in Site Reliability Engineering, O'Reilly Media, 2016. https://sre.google/sre-book/monitoring-distributed-systems/
[5] Prometheus Authors, "Prometheus — Monitoring system & time series database," CNCF Graduated Project, 2024. https://prometheus.io/docs/introduction/overview/
[6] B. H. Sigelman et al., "Dapper, a Large-Scale Distributed Systems Tracing Infrastructure," Google Technical Report, 2010. https://research.google/pubs/dapper-a-large-scale-distributed-systems-tracing-infrastructure/
[7] OpenTelemetry Authors, "OpenTelemetry Documentation," CNCF, 2025. https://opentelemetry.io/docs/
[8] C. Sridharan, Distributed Systems Observability, O'Reilly Media, 2018. https://www.oreilly.com/library/view/distributed-systems-observability/9781492033431/
[9] B. Gregg, "The USE Method," 2024. https://www.brendangregg.com/usemethod.html
[10] W3C, "Trace Context — W3C Recommendation," 2024. https://www.w3.org/TR/trace-context/
[11] OpenTelemetry Authors, "OTLP Specification 1.10.0," 2025. https://opentelemetry.io/docs/specs/otlp/
[12] B. Beyer et al., "Implementing SLOs," in The Site Reliability Workbook, O'Reilly Media, 2018. https://sre.google/workbook/implementing-slos/
[13] B. Beyer et al., "Alerting on SLOs," in The Site Reliability Workbook, O'Reilly Media, 2018. https://sre.google/workbook/alerting-on-slos/