Tracciamento distribuito in un'applicazione di microservizi

Last reviewed 2024-06-26 UTC

Questo documento è il quarto di una serie in quattro parti sulla progettazione, sulla creazione e sul deployment dei microservizi. Questa serie descrive i vari elementi di una di microservizi. La serie include informazioni sui vantaggi e sugli svantaggi del pattern di architettura di microservizi e su come applicarlo.

  1. Introduzione ai microservizi
  2. Eseguire il refactoring di un monolite in microservizi
  3. Comunicazione tra servizi in una configurazione di microservizi
  4. Tracciamento distribuito in un'applicazione di microservizi (questo documento)

Questa serie è rivolta a sviluppatori e architetti di applicazioni che progettano e implementano la migrazione per eseguire il refactoring di un'applicazione monolitica in un'applicazione di microservizi.

In un sistema distribuito, è importante sapere come una richiesta passa da un servizio all'altro e il tempo necessario per eseguire un'attività in ogni servizio. Considera l'applicazione Online Boutique basata su microservizi di cui hai eseguito il deployment nel documento precedente, Esegui il refactoring di un monolite in microservizi. L'applicazione è composta da più servizi. Ad esempio, screenshot mostra la pagina dei dettagli del prodotto, che recupera informazioni dalla il frontend, i consigli e i servizi pubblicitari.

La pagina dei dettagli del prodotto.

Per eseguire il rendering della pagina dei dettagli del prodotto, il servizio di frontend comunica con come mostrato nel diagramma seguente:

Il servizio di frontend comunica con il servizio di consigli, il catalogo dei prodotti e il servizio di annunci.

Figura 1. Servizi scritti in lingue diverse.

Nella figura 1, il servizio di frontend è scritto in Go. Il consiglio scritto in Python, utilizza gRPC per comunicare con il frontend completamente gestito di Google Cloud. Il servizio annunci, scritto in Java, utilizza anche gRPC per comunicare con il servizio frontend. Oltre a gRPC, il metodo di comunicazione tra servizi può essere anche in REST HTTP.

Quando crei un sistema distribuito di questo tipo, vuoi che i tuoi strumenti di osservabilità fornisce le seguenti informazioni:

  • I servizi attraverso i quali è passata una richiesta.
  • Dove si sono verificati ritardi se una richiesta era lenta.
  • Dove si è verificato un errore se la richiesta non è andata a buon fine.
  • In che modo l'esecuzione della richiesta era diversa dal comportamento normale del sistema.
  • Se le differenze nell'esecuzione della richiesta erano correlate a rendimento (se alcune chiamate di servizio hanno richiesto un tempo più lungo o più breve rispetto al solito).

Obiettivi

  • Utilizza i file manifest di Kustomize per configurare l'infrastruttura.
  • Esegui il deployment dell'applicazione di esempio Online Boutique in Google Kubernetes Engine (GKE).
  • Utilizzare Cloud Trace per esaminare il percorso di un utente nell'applicazione di esempio.

Costi

In questo documento utilizzi i seguenti componenti fatturabili di Google Cloud:

Per generare una stima dei costi basata sull'utilizzo previsto, utilizza il Calcolatore prezzi. I nuovi utenti di Google Cloud potrebbero essere idonei per una prova gratuita.

Al termine di questo documento, per evitare che la fatturazione continui eliminando il le risorse che hai creato. Per ulteriori informazioni, vedi Eseguire la pulizia.

Prima di iniziare

Se hai già configurato un progetto completando il documento precedente in questo serie, Comunicazione tra servizi in una configurazione di microservizi, puoi riutilizzare il progetto. Completa i seguenti passaggi per attivare le API e impostare le variabili di ambiente.

  1. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  2. Make sure that billing is enabled for your Google Cloud project.

  3. In the Google Cloud console, activate Cloud Shell.

    Activate Cloud Shell

  4. Abilita le API per Compute Engine, GKE, Cloud SQL, Artifact Analysis, Trace e Container Registry:

     gcloud services enable \
       compute.googleapis.com \
       sql-component.googleapis.com \
       servicenetworking.googleapis.com\
       container.googleapis.com \
       containeranalysis.googleapis.com \
       containerregistry.googleapis.com \
       sqladmin.googleapis.com
    

Tracciamento distribuito

Il tracciamento distribuito collega i metadati contestuali a ogni richiesta e garantisce per far sì che i metadati vengano condivisi tra le richieste. Puoi usare i punti traccia per allo strumento distribuito il tracciamento. Ad esempio, puoi instrumentare i tuoi servizi (frontend, suggerimento e annunci) con due punti di traccia per gestire la richiesta del cliente visualizza i dettagli di un prodotto: un punto di traccia per inviare la richiesta e un'altra punto per ricevere la risposta. Il seguente diagramma mostra come questo punto di traccia della strumentazione:

Una strumentazione dei punti di traccia con due punti di traccia.

Figura 2. Ogni chiamata tra servizi ha due punti di traccia costituiti da una coppia di richiesta/risposta.

Per consentire ai punti di traccia di capire quale richiesta eseguire quando il servizio viene richiamato, il servizio di origine passa un ID traccia durante il flusso di esecuzione. Il processo che passa l'ID traccia è chiamato propagazione dei metadati o propagazione del contesto distribuito. La propagazione del contesto trasferisce i metadati quando i servizi di un'applicazione distribuita comunicano durante l'esecuzione di una determinata richiesta. Il seguente diagramma mostra la propagazione dei metadati:

La propagazione dei metadati passa l'ID traccia.

Figura 3. I metadati di Trace vengono trasmessi tra i servizi. I metadati includono informazioni come i servizi che chiamano altri servizi e i relativi timestamp.

Nell'esempio della boutique online, una traccia inizia quando un utente invia una richiesta iniziale per recuperare i dettagli del prodotto. Viene generato un nuovo ID traccia, per le richieste successive sono decorate con intestazioni che contengono metadati contestuali alla richiesta originale.

Ogni singola operazione invocata nell'ambito dell'evasione della richiesta dell'utente finale è chiamata span. Il servizio di origine tag di ogni intervallo con il proprio l'ID univoco e l'ID traccia dell'intervallo padre. Il seguente diagramma mostra un Visualizzazione del diagramma di Gantt di una traccia:

Le singole operazioni sono taggate come intervalli.

Figura 4. Uno span principale include il tempo di risposta degli span secondari.

La figura 4 mostra un tracealbero in cui il servizio frontend chiama di suggerimenti e annunci. Il servizio frontend è l'elemento padre che descrive il tempo di risposta osservato dall'utente finale. Gli elementi figli descrivono in che modo sono stati chiamati e hanno risposto il servizio di consigli e il servizio pubblicitario, incluse le informazioni sui tempi di risposta.

Un mesh di servizi come Istio consente il tracciamento distribuito del traffico tra i servizi senza la necessità di con qualsiasi strumentazione dedicata. Tuttavia, potrebbero verificarsi situazioni in cui Se vuoi avere un maggiore controllo sulle tracce, potresti dover tracciare il codice non è in esecuzione all'interno di un mesh di servizi.

Questo documento utilizza OpenTelemetry abilitare la strumentazione delle applicazioni basate su microservizi distribuiti analisi e metriche. OpenTelemetry consente di raccogliere metriche e tracce e quindi esportali in backend, come Prometheus, Cloud Monitoring, Datadog, Graphite, Zipkin e Jaeger.

Strumentazione con OpenTelemetry

Le seguenti sezioni mostrano come utilizzare la propagazione del contesto per consentire intervalli da più richieste da aggiungere a una singola traccia padre.

Questo esempio utilizza le librerie OpenTelemetry per JavaScript, Python e Go per instrumentare l'implementazione della traccia per i servizi di pagamento, consigli e frontend. A seconda del livello di dettaglio della strumentazione, il tracciamento i dati possono influire sul costo del progetto (fatturazione Cloud Trace). Per ridurre problemi di costo, la maggior parte dei sistemi di tracciamento utilizza varie forme di campionamento per catturare solo una certa percentuale delle tracce osservate. Negli ambienti di produzione, la tua organizzazione potrebbe avere motivi per scegliere cosa campionare e perché. Potresti voler personalizzare la tua strategia di campionamento in base alla gestione dei costi, concentrandoti su tracce interessanti o filtrando il rumore. Per scoprire di più sul campionamento, consulta Campionamento OpenTelemetry.

Questo documento utilizza Traccia per visualizzare le tracce distribuite. Puoi utilizzare un esportatore OpenTelemetry per inviare tracce in Trace.

Registra esportatori di tracce

Questa sezione mostra come registrare l'esportatore tracce in ogni servizio aggiungendo al codice del microservizio.

Per il servizio frontend (scritto in Go), il seguente esempio di codice registra l'esportatore:

[...]
exporter, err := otlptracegrpc.New(
        ctx,
        otlptracegrpc.WithGRPCConn(svc.collectorConn))
    if err != nil {
        log.Warnf("warn: Failed to create trace exporter: %v", err)
    }
tp := sdktrace.NewTracerProvider(
        sdktrace.WithBatcher(exporter),
        sdktrace.WithSampler(sdktrace.AlwaysSample()))
    otel.SetTracerProvider(tp)

Per il servizio di suggerimenti (scritto in Python), il seguente esempio di codice registra l'esportatore:

if os.environ["ENABLE_TRACING"] == "1":
    trace.set_tracer_provider(TracerProvider())
    otel_endpoint = os.getenv("COLLECTOR_SERVICE_ADDR", "localhost:4317")
    trace.get_tracer_provider().add_span_processor(
        BatchSpanProcessor(
            OTLPSpanExporter(
            endpoint = otel_endpoint,
            insecure = True
            )
        )
    )

Per il servizio di pagamento (scritto in JavaScript), il seguente esempio di codice registra l'esportatore:

provider.addSpanProcessor(new SimpleSpanProcessor(new OTLPTraceExporter({url: collectorUrl})));
provider.register();

Configura la propagazione del contesto

Il sistema di tracciamento deve seguire una specifica del contesto di traccia che definisce il formato per propagare il contesto di tracciamento tra i servizi. Alcuni esempi di formato di propagazione includono il formato B3 di Zipkin e X-Google-Cloud-Trace.

OpenTelemetry propaga il contesto utilizzando il parametro TextMapPropagator globale. In questo esempio viene utilizzato il propagatore del contesto di traccia, che usa il formato traceparent W3C. Le librerie di strumentazione, come le librerie HTTP e gRPC di OpenTelemetry, utilizzano il propagatore globale per aggiungere il contesto della traccia come metadati alle richieste HTTP o gRPC. Affinché la propagazione del contesto abbia esito positivo, il client e il server devono utilizzare lo stesso formato di propagazione.

Propagazione del contesto tramite HTTP

Il servizio di frontend inserisce un contesto di traccia nella richiesta HTTP intestazioni. I servizi di backend estraggono il contesto della traccia. Il seguente esempio di codice mostra come servizio frontend è instrumentato per configurare il contesto della traccia:

otel.SetTextMapPropagator(
    propagation.NewCompositeTextMapPropagator(
        propagation.TraceContext{}, propagation.Baggage{}))

if os.Getenv("ENABLE_TRACING") == "1" {
    log.Info("Tracing enabled.")
    initTracing(log, ctx, svc)
} else {
    log.Info("Tracing disabled.")
}

...

var handler http.Handler = r
handler = &logHandler{log: log, next: handler}     // add logging
handler = ensureSessionID(handler)                 // add session ID
handler = otelhttp.NewHandler(handler, "frontend") // add OpenTelemetry tracing

Propagazione del contesto tramite gRPC

Considera il flusso in cui il servizio di pagamento effettua l'ordine in base al prodotto selezionato da un utente. Questi servizi comunicano tramite gRPC.

Il seguente esempio di codice utilizza un intercettatore di chiamate gRPC che intercetta la chiamata in uscita chiama e inserisce il contesto della traccia:

var srv *grpc.Server

// Propagate trace context always
otel.SetTextMapPropagator(
    propagation.NewCompositeTextMapPropagator(
        propagation.TraceContext{}, propagation.Baggage{}))
srv = grpc.NewServer(
    grpc.UnaryInterceptor(otelgrpc.UnaryServerInterceptor()),
    grpc.StreamInterceptor(otelgrpc.StreamServerInterceptor()),
)

Dopo aver ricevuto la richiesta, il servizio di pagamento o del catalogo dei prodotti (ListProducts) estrae il contesto dalle intestazioni della richiesta e utilizza i metadati della traccia principale per generare uno span secondario.

Le seguenti sezioni forniscono dettagli su come configurare ed esaminare tracciamento dell'applicazione di esempio Online Boutique.

Esegui il deployment dell'applicazione

Se hai già un'applicazione in esecuzione per completare il documento precedente di questa serie, Comunicazione tra servizi in una configurazione di microservizi, puoi passare alla sezione successiva, Esamina le tracce. In caso contrario, completa i seguenti passaggi per eseguire il deployment dell'esempio di boutique online:

  1. Per configurare l'infrastruttura, clona GitHub in Cloud Shell repository:

    git clone https://github.com/GoogleCloudPlatform/microservices-demo.git
    
  2. Per il nuovo deployment, reimposta le variabili di ambiente:

    PROJECT_ID=PROJECT_ID
    REGION=us-central1
    GSA_NAME=microservices-sa
    GSA_EMAIL=$GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com
    

    Sostituisci PROJECT_ID con l'ID progetto Google Cloud che vuoi utilizzare.

  3. (Facoltativo) Crea un nuovo cluster o riutilizzane uno esistente, se esistente:

    gcloud container clusters create-auto online-boutique --project=${PROJECT_ID}
      --region=${REGION}
    
  4. Crea un account di servizio Google:

    gcloud iam service-accounts create $GSA_NAME \
      --project=$PROJECT_ID
    
  5. Abilita le API:

    gcloud services enable \
    monitoring.googleapis.com \
    cloudtrace.googleapis.com \
    cloudprofiler.googleapis.com \
      --project ${PROJECT_ID}
    
  6. Concedi all'account di servizio i ruoli richiesti per Cloud Trace:

    gcloud projects add-iam-policy-binding ${PROJECT_ID} \
    --member "serviceAccount:${GSA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com" \
    --role roles/cloudtrace.agent
    
    gcloud projects add-iam-policy-binding ${PROJECT_ID} \
    --member "serviceAccount:${GSA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com" \
    --role roles/monitoring.metricWriter
    
    gcloud projects add-iam-policy-binding ${PROJECT_ID} \
    --member "serviceAccount:${GSA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com" \
    --role roles/cloudprofiler.agent
    
    gcloud iam service-accounts add-iam-policy-binding ${GSA_EMAIL} \
    --role roles/iam.workloadIdentityUser \
    --member "serviceAccount:${PROJECT_ID}.svc.id.goog[default/default]"
    
  7. Annota l'account di servizio Kubernetes (default/default per predefinito) per utilizzare l'account di servizio Identity and Access Management (IAM):

    kubectl annotate serviceaccount default \
        iam.gke.io/gcp-service-account=${GSA_EMAIL}
    
  8. Attiva la configurazione di Google Cloud Observability per GKE, che abilita il monitoraggio:

    cd ~/microservices-demo/kustomize && \
    kustomize edit add component components/google-cloud-operations
    

    Il comando precedente aggiorna il file kustomize/kustomization.yaml, che è simile al seguente:

    apiVersion: kustomize.config.k8s.io/v1beta1
    kind: Kustomization
    resources:
    - base
    components:
    - components/google-cloud-operations
    [...]
    
  9. Esegui il deployment dei microservizi:

    kubectl apply -k .
    
  10. Controlla lo stato del deployment:

    kubectl rollout status deployment/frontend
    kubectl rollout status deployment/paymentservice
    kubectl rollout status deployment/recommendationservice
    kubectl rollout status deployment/adservice
    

    L'output di ciascun comando è simile al seguente:

    Waiting for deployment "" rollout to finish: 0 of 1 updated replicas are available...
    deployment "" successfully rolled out
    
  11. Ottieni l'indirizzo IP dell'applicazione di cui è stato eseguito il deployment:

    kubectl get service frontend-external | awk '{print $4}'
    

    Attendi che l'indirizzo IP del bilanciatore del carico venga pubblicato. Per uscire dal comando, premere Ctrl+C. Prendi nota dell'indirizzo IP del bilanciatore del carico e accedi all'applicazione all'URL http://IP_ADDRESS. Potrebbe essere necessario un po' di tempo prima che il bilanciatore del carico diventi stabile e inizi a inoltrare il traffico.

Rivedi le tracce utilizzando Cloud Trace

Il percorso di acquisto di un utente nell'applicazione Online Boutique ha il seguente flusso:

  • L'utente vede un catalogo di prodotti nella pagina di destinazione.
  • Per effettuare un acquisto, l'utente fa clic su Acquista.
  • L'utente viene reindirizzato a una pagina dei dettagli del prodotto in cui aggiunge l'articolo al carrello.
  • L'utente viene reindirizzato a una pagina di pagamento in cui può effettuare un pagamento per completare l'ordine.

Considera uno scenario in cui devi risolvere i problemi relativi ai tempi di risposta elevati durante il caricamento della pagina dei dettagli del prodotto. Come descritto in precedenza, la pagina dei dettagli del prodotto è composta da più microservizi. Per determinare dove e perché si verifica la latenza elevata, puoi visualizzare i grafici di monitoraggio distribuito per esaminare le prestazioni dell'intera richiesta nei diversi servizi.

Per esaminare il grafici di tracciamento distribuito, procedi nel seguente modo:

  1. Accedi all'applicazione e fai clic su un prodotto qualsiasi. I dettagli del prodotto .
  2. Nella console Google Cloud, vai alla Elenco di tracce ed esaminare la cronologia.
  3. Per vedere i risultati della traccia distribuita, fai clic su Frontend nella colonna URI.
  4. La vista a cascata Trace mostra gli intervalli associati all'URI:

    La visualizzazione della traccia a cascata mostra gli intervalli.

    Nello screenshot precedente, la traccia di un prodotto contiene i seguenti intervalli:

    • L'intervallo Frontend acquisisce la latenza end-to-end (150.349 ms) rilevata dal client durante il caricamento della pagina dei dettagli del prodotto.
    • L'intervallo Servizio di consigli acquisisce la latenza delle chiamate di backend per il recupero dei consigli (4.246 ms) correlati al prodotto.
    • L'intervallo Servizio annunci acquisisce la latenza delle chiamate di backend per recuperare gli annunci (4.511 ms) pertinenti alla pagina del prodotto.

Per risolvere i problemi relativi ai tempi di risposta elevati, puoi esaminare gli approfondimenti includono i grafici di distribuzione della latenza di eventuali richieste outlier quando le dipendenze non soddisfano obiettivi del livello di servizio (SLO). Puoi anche utilizzare Cloud Trace per ottenere approfondimenti sul rendimento e creare report di analisi dai dati campionati.

Risoluzione dei problemi

Se le tracce in Application Performance Management non vengono visualizzate, controlla in Esplora log se è presente un errore di autorizzazione negata. L'autorizzazione si verifica quando l'account di servizio non ha accesso per esportare le tracce. Rivedi i passaggi su assegnare i ruoli richiesto per Cloud Trace e di annotare l'account di servizio con lo spazio dei nomi corretto. Dopodiché, riavvia opentelemetrycollector:

  kubectl rollout restart deployment opentelemetrycollector

Esegui la pulizia

Per evitare che al tuo account Google Cloud vengano addebitati costi relativi alle risorse utilizzate in questo tutorial, elimina il progetto che contiene le risorse oppure mantieni il progetto ed elimina le singole risorse.

Elimina il progetto

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

Elimina le risorse

Se vuoi mantenere il progetto Google Cloud utilizzato in questo documento, elimina le singole risorse:

  • In Cloud Shell, elimina le risorse:

    gcloud container clusters delete online-boutique --project=${PROJECT_ID} --region=${REGION}
    

Passaggi successivi