CodeGym /Corsi /C# SELF /Tracciamento distribuito e telemetria

Tracciamento distribuito e telemetria

C# SELF
Livello 64, Lezione 4
Disponibile

1. Introduzione

Nel mondo moderno dell'architettura orientata ai servizi (SOA), dei microservizi e delle soluzioni cloud, una singola richiesta utente può "volare" attraverso decine di servizi prima di restituire il risultato. Ogni nodo di questo "percorso" scrive i suoi log, ma come capire che un errore o un ritardo in un punto è effettivamente collegato a quella specifica richiesta?

Il tracciamento distribuito è come un sistema di tracking per un pacco nella logistica: vedi attraverso quali punti è passato il tuo pacco, dove si è fermato e dove è successo un imprevisto. Nel mondo della programmazione — è la possibilità di seguire il "viaggio" di una singola richiesta attraverso tutti i servizi, capire quanto tempo ha passato in ciascun punto e dove si è verificato un errore o un ritardo.

Perché serve il tracciamento?

  • Localizzazione degli errori: Se qualcosa va storto, vedi subito dove esattamente: in quale servizio, in quale fase e persino quale metodo specifico è stato chiamato.
  • Ricerca dei "colli di bottiglia": Il tracciamento mostrerà dove i tuoi servizi "rallentano" e in quale fase si perde più tempo.
  • Analisi degli scenari d'uso: Si può capire come i clienti usano realmente i tuoi servizi e dove vale la pena investire per ottimizzare prima di tutto.

Come funziona?

Ogni richiesta riceve un identificatore univoco di trace (TraceId), che "viaggia" con essa lungo tutto lo stack di servizi: dal frontend al backend, dall'API al database e ritorno. Ad ogni fase vengono creati degli "span" (spans) che registrano il tempo di esecuzione dell'operazione e eventi aggiuntivi. Alla fine ottieni un albero (grafo) di operazioni con le loro durate e le relazioni tra di esse.

Entità chiave e termini del tracciamento distribuito

Termine Descrizione
Trace Percorso logico di una singola richiesta attraverso più servizi. Unico per TraceId.
Span Operazione o sotto-operazione all'interno di una trace. Ogni span ha il suo identificatore univoco.
TraceId Identificatore univoco dell'intera trace (della richiesta).
SpanId Identificatore univoco dello span corrente (dell'operazione).
Parent SpanId Id dello span genitore (se questo span è parte di un'altra operazione).
Attributes Insieme di metadata custom per lo span: nome del metodo, parametri, stato ecc.
Events/Logs Eventi importanti legati allo span (per esempio, errore, completamento).
Context Propagation Trasferimento delle informazioni della trace tra servizi e thread.

2. OpenTelemetry: standard aperto per l'osservabilità

Breve su OpenTelemetry

OpenTelemetry — standard aperto e set di strumenti per la raccolta di telemetria (tracce, metriche, log) da applicazioni varie. È supportato dalla Cloud Native Computing Foundation (CNCF) ed è diventato lo standard de-facto nel mondo delle applicazioni cloud e distribuite.

OpenTelemetry (abbreviato OTel) sa fare:

  • Raccogliere e inviare automaticamente trace, metriche e log;
  • Lavorare con i principali linguaggi di programmazione, inclusi C#, Java, Python e altri;
  • Inviare i dati ai sistemi di osservabilità — Jaeger, Zipkin, Azure Monitor, Grafana ecc.;
  • Estendersi tramite plugin e configurarsi per qualsiasi stack.

Perché proprio OpenTelemetry?

  • Indipendenza dal vendor: OTel è uno standard, non il prodotto di una singola azienda.
  • Compatibilità: Supporta i principali formati di tracciamento, si integra facilmente con sistemi APM.
  • Automazione: Gran parte del lavoro (per esempio il tracciamento delle richieste HTTP) può essere fatto automaticamente con minima configurazione.
  • Scalabilità: OTel funziona bene sia in sistemi piccoli che in grandi ambienti.

Architettura OpenTelemetry: semplice

Per non perdersi tra i "layer", visualizziamo il tipico flusso dati di tracing in OTel.

flowchart LR
    subgraph Applicazione
        A[OpenTelemetry SDK]
    end
    A -->|Tracce, metriche, log| B[OpenTelemetry Collector]
    B -->|Export verso| C[Jaeger/Zipkin/Grafana/Azure/Application Insights ecc.]
  1. OpenTelemetry SDK: Si integra direttamente nella tua applicazione (per esempio tramite pacchetti NuGet per .NET).
  2. OTel Collector: Servizio concentratore separato (spesso deployato come container Docker), che accetta i dati di trace da tutte le tue applicazioni ed effettua l'export dove specifichi.
  3. Frontend di osservabilità: Sistema dove vedi grafici, alberi, filtri e analizzi le trace.

3. Quick start con il tracciamento in C#/.NET

Aggiungiamo il tracciamento distribuito di base nella nostra applicazione didattica. I passaggi principali sono piuttosto semplici.

Installiamo i pacchetti NuGet

dotnet add package OpenTelemetry
dotnet add package OpenTelemetry.Exporter.Console

OpenTelemetry — implementazione base dello SDK;
OpenTelemetry.Exporter.Console — export delle trace sulla console (puoi sostituirlo con Jaeger, Zipkin ecc.).

Configurazione minima del tracciamento

Nel file Program.cs (per un'app console):

using OpenTelemetry;
using OpenTelemetry.Trace;

class Program
{
    static void Main(string[] args)
    {
        // Configuriamo il tracciamento
        using var tracerProvider = Sdk.CreateTracerProviderBuilder()
            .AddSource("DemoApp") // Specifichiamo il nome della source
            .AddConsoleExporter() // Esportiamo le trace sulla console
            .Build();

        var source = new System.Diagnostics.ActivitySource("DemoApp");

        // Avviamo una nuova trace (span radice)
        using (var activity = source.StartActivity("Operazione principale"))
        {
            DoWork();
        }
    }

    static void DoWork()
    {
        // Un po' di logica dell'app...
        System.Threading.Thread.Sleep(300);
    }
}

Cosa succede qui?

  • Creiamo un provider di tracing, registriamo la source ("DemoApp") e aggiungiamo il console exporter AddConsoleExporter().
  • Avviamo una nuova "activity" (span) tramite ActivitySource nel punto radice del programma.
  • All'interno eseguiamo il lavoro utile che vogliamo tracciare.

Risultato:

Activity.Id:          0b69e3e97ca5f14d
Activity.Operation:   Operazione principale
Duration: 00:00:00.3001082
...

Tracciamento automatico di HTTP e database

OpenTelemetry supporta l'instrumentation — tracciamento automatico di librerie popolari. Per esempio, le chiamate fatte tramite HttpClient e le query al DB (ADO.NET) possono essere raccolte senza modifiche al tuo codice.

using var tracerProvider = Sdk.CreateTracerProviderBuilder()
    .AddHttpClientInstrumentation() // Richieste HTTP
    .AddSqlClientInstrumentation()  // Query SQL (se le usi)
    .AddConsoleExporter()
    .Build();

Ora tutte le tue chiamate tramite HttpClient e le operazioni SQL appariranno automaticamente nelle trace.

4. Visualizzazione del tracciamento

L'output sulla console è solo il primo passo. Per sfruttarlo davvero è meglio usare un frontend con visualizzazione.

Jaeger

Jaeger è uno dei sistemi open-source più popolari per visualizzare le trace.

  1. Deployi Jaeger (per esempio via Docker).
  2. Al posto di AddConsoleExporter() usi:
    .AddJaegerExporter(options =>
    {
        options.AgentHost = "localhost";
        options.AgentPort = 6831;
    })
    
  3. Ora tutte le trace saranno visibili nell'interfaccia di Jaeger — puoi filtrare per TraceId, vedere diagrammi temporali dettagliati.

Guida completa: OpenTelemetry Jaeger Exporter per .NET

5. Consigli pratici

Confronto degli approcci

Senza OTel copi manualmente il TraceId nei log, speri di non dimenticarti di passarlo avanti e soffri quando analizzi gli incidenti. Con OTel tutta la catena si costruisce automaticamente e si visualizza con un click.

Approccio Sforzo Affidabilità Scalabilità Compatibilità
Log manuale di TraceId Alto Bassa Richiede manutenzione continua Solo le tue applicazioni
OpenTelemetry Minimo (dopo l'adozione) Garantita Ampia (qualsiasi linguaggio, stack) Compatibile con la maggior parte di APM e sistemi di log

Esempio di architettura

[Client web] --> [API service] --> [Auth service] --> [Database service]

Quando l'utente clicca un pulsante, la richiesta attraversa tutti questi servizi. Con OTel puoi "tirare il filo" (TraceId) attraverso ognuno di essi, unendo automaticamente la logica in una singola trace.

  • In ogni servizio lo SDK OTel riconosce automaticamente il TraceId dagli header HTTP e continua la catena.
  • Di conseguenza puoi aprire una trace e vedere dove sono stati spesi i millisecondi, cosa è successo e dove si è verificato un errore.

Uso in progetti reali e nei colloqui

  • Sistemi basati su microservizi e applicazioni distribuite (fintech, marketplace, SaaS ecc.).
  • DevOps/SRE: localizzazione rapida dei problemi.
  • Miglioramento degli SLA e della reattività dei servizi.
  • Profiling e ottimizzazione.
  • Ai colloqui — dimostrazione di pratiche ingegneristiche mature.

6. Errori tipici e caratteristiche dell'implementazione

Dimenticare di passare il TraceContext. Se tra i servizi non viene passato il TraceId (per esempio, dimentichi di inoltrare gli header HTTP necessari), le trace si romperanno — appariranno come "punti" isolati e tutta l'utilità dell'osservabilità andrà persa.

Codice non instrumentato. Se una tua libreria o framework non supporta l'instrumentation, alcune operazioni usciranno dalla trace (ma puoi sempre creare gli span manualmente tramite ActivitySource e StartActivity()).

Eccesso di dati. Raccogliere trace per ogni richiesta è costoso, specialmente in produzione su larga scala. Di solito si abilita il tracciamento solo per una parte delle richieste (sample rate) o su trigger (errori, richieste lente).

Prestazioni. L'adozione di OTel impatta minimamente le performance se si usa esportazione asincrona; tuttavia in caso di traffico molto elevato monitorare l'overhead e regolare il sampling è importante.

2
Compito
C# SELF, livello 64, lezione 4
Bloccato
Implementazione di una traccia minima con OpenTelemetry
Implementazione di una traccia minima con OpenTelemetry
1
Sondaggio/quiz
Logging, livello 64, lezione 4
Non disponibile
Logging
Logging, monitoring e tracing
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION