Informazioni su questo codelab
1. Introduzione
Ultimo aggiornamento: 15-07-2022
Osservabilità dell'applicazione
Osservabilità e OpenTelemetry
Osservabilità è il termine utilizzato per descrivere un attributo di un sistema. Un sistema con osservabilità consente ai team di eseguire attivamente il debug del sistema. In questo contesto, esistono tre pilastri dell'osservabilità: log, metriche e tracce sono la strumentazione fondamentale che il sistema utilizza per acquisire l'osservabilità.
OpenTelemetry è un insieme di specifiche, librerie e agenti che accelerano la strumentazione e l'esportazione di dati di telemetria (log, metriche e tracce) richiesti dall'osservabilità. OpenTelemetry è uno standard aperto e un progetto guidato dalla community all'interno del CNCF. Utilizzando le librerie fornite dal progetto e dal suo ecosistema, gli sviluppatori sono in grado di instrumentare le loro applicazioni in modo indipendente dal fornitore e su più architetture.
Inoltre, oltre ai tre pilastri dell'osservabilità, la profilazione continua è un altro componente fondamentale per l'osservabilità e sta espandendo la base utenti nel settore. Cloud Profiler è uno dei originatori e fornisce un'interfaccia semplice per visualizzare in dettaglio le metriche delle prestazioni negli stack di chiamate delle applicazioni.
Questo codelab è la prima parte della serie e riguarda l'utilizzo degli strumenti di tracce distribuite nei microservizi con OpenTelemetry e Cloud Trace. La Parte 2 tratterà la profilazione continua con Cloud Profiler.
Traccia distribuita
Tra log, metriche e tracce, la traccia è la telemetria che indica la latenza di una parte specifica del processo nel sistema. In particolare nell'era dei microservizi, le tracce distribuite sono il fattore chiave per individuare i colli di bottiglia della latenza nell'intero sistema distribuito.
Quando si analizzano le tracce distribuite, la visualizzazione dei dati di traccia è fondamentale per comprendere a colpo d'occhio le latenze complessive del sistema. Nella traccia distribuita, gestiamo un insieme di chiamate per elaborare una singola richiesta al punto di ingresso del sistema sotto forma di traccia contenente più intervalli.
L'intervallo rappresenta una singola unità di lavoro svolto in un sistema distribuito, che registra i tempi di inizio e di fine. Gli intervalli hanno spesso relazioni gerarchiche tra loro. Nella figura seguente, tutti gli intervalli più piccoli sono intervalli figlio di un grande intervallo /messages e sono assemblati in un'unica traccia che mostra il percorso di lavoro attraverso un sistema.
Google Cloud Trace è una delle opzioni per il backend di traccia distribuita ed è ben integrato con altri prodotti di Google Cloud.
Cosa creerai
In questo codelab, accederai alle informazioni di traccia degli strumenti nei servizi chiamati "applicazione Shakespeare" (Shakesapp) in esecuzione su un cluster Google Kubernetes Engine. L'architettura di Shakesapp è descritta di seguito:
- Loadgen invia una stringa di query al client in HTTP
- I client passano attraverso la query dal loadgen al server in gRPC
- Il server accetta la query dal client, recupera tutte le opere di Shakespare in formato testo da Google Cloud Storage, cerca le righe che contengono la query e restituisce il numero della riga corrispondente al client
Potrai instrumentare le informazioni di traccia nella richiesta. Successivamente, incorporerai un agente profiler nel server ed analizzerai il collo di bottiglia.
Cosa imparerai a fare
- Come iniziare a utilizzare le librerie di Trace OpenTelemetry nel progetto Go
- Come creare un intervallo con la libreria
- Come propagare i contesti di intervallo lungo il cavo tra i componenti dell'app
- Come inviare dati di traccia a Cloud Trace
- Come analizzare la traccia su Cloud Trace
Questo codelab spiega come instrumentare i tuoi microservizi. Per essere più comprensibile, questo esempio contiene solo tre componenti (generatore di carico, client e server), ma puoi applicare la stessa procedura spiegata in questo codelab a sistemi più complessi e di grandi dimensioni.
Che cosa ti serve
- Conoscenza di base di Go
- Conoscenza di base di Kubernetes
2. Configurazione e requisiti
Configurazione dell'ambiente da seguire in modo autonomo
Se non disponi già di un account Google (Gmail o Google Apps), devi crearne uno. Accedi alla console della piattaforma Google Cloud ( console.cloud.google.com) e crea un nuovo progetto.
Se hai già un progetto, fai clic sul menu a discesa per la selezione del progetto in alto a sinistra nella console:
e fai clic su "NUOVO PROGETTO" nella finestra di dialogo risultante per creare un nuovo progetto:
Se non hai ancora un progetto, dovresti visualizzare una finestra di dialogo come questa per crearne uno:
La finestra di dialogo di creazione del progetto successiva ti consente di inserire i dettagli del nuovo progetto:
Ricorda l'ID progetto, che è un nome univoco tra tutti i progetti Google Cloud (il nome precedente è già in uso e non funzionerà per te). Verrà indicato più avanti in questo codelab come PROJECT_ID.
Successivamente, se non l'hai ancora fatto, dovrai abilitare la fatturazione in Developers Console per utilizzare le risorse Google Cloud e abilitare l'API Cloud Trace.
L'esecuzione di questo codelab non dovrebbe costare più di qualche euro, ma potrebbe essere più costoso se decidi di utilizzare più risorse o se le lasci in esecuzione (consulta la sezione relativa alla pulizia alla fine di questo documento). I prezzi di Google Cloud Trace, Google Kubernetes Engine e Google Artifact Registry sono riportati nella documentazione ufficiale.
- Prezzi della suite operativa di Google Cloud | Suite operativa
- Prezzi | Documentazione di Kubernetes Engine
- Prezzi di Artifact Registry | documentazione di Artifact Registry
I nuovi utenti della piattaforma Google Cloud hanno diritto a una prova senza costi di 300$, che dovrebbe rendere questo codelab completamente senza costi.
Configurazione di Google Cloud Shell
Mentre Google Cloud e Google Cloud Trace possono essere gestiti da remoto dal tuo laptop, in questo codelab utilizzeremo Google Cloud Shell, un ambiente a riga di comando in esecuzione nel cloud.
Questa macchina virtuale basata su Debian viene caricata con tutti gli strumenti di sviluppo necessari. Offre una home directory permanente da 5 GB e viene eseguita in Google Cloud, migliorando notevolmente le prestazioni di rete e l'autenticazione. Ciò significa che per questo codelab è sufficiente un browser (sì, funziona su Chromebook).
Per attivare Cloud Shell dalla console Cloud, fai clic su Attiva Cloud Shell (il provisioning e la connessione all'ambiente dovrebbero richiedere solo pochi minuti).
Dopo la connessione a Cloud Shell, dovresti vedere che hai già eseguito l'autenticazione e che il progetto è già impostato su PROJECT_ID
.
gcloud auth list
Output comando
Credentialed accounts: - <myaccount>@<mydomain>.com (active)
gcloud config list project
Output comando
[core] project = <PROJECT_ID>
Se, per qualche motivo, il progetto non è impostato, invia semplicemente il seguente comando:
gcloud config set project <PROJECT_ID>
Stai cercando il tuo PROJECT_ID
? Controlla l'ID utilizzato nei passaggi di configurazione o cercalo nella dashboard della console Cloud:
Cloud Shell imposta anche alcune variabili di ambiente per impostazione predefinita, cosa che può essere utile quando eseguirai comandi futuri.
echo $GOOGLE_CLOUD_PROJECT
Output comando
<PROJECT_ID>
Infine, imposta la zona e la configurazione del progetto predefinite.
gcloud config set compute/zone us-central1-f
Puoi scegliere zone diverse. Per ulteriori informazioni, consulta Regioni e Zone.
Configurazione della lingua di Go
In questo codelab, utilizziamo Go per tutto il codice sorgente. Esegui questo comando su Cloud Shell e verifica che la versione di Go sia 1.17 o successiva
go version
Output comando
go version go1.18.3 linux/amd64
Configura un cluster Google Kubernetes
In questo codelab, eseguirai un cluster di microservizi su Google Kubernetes Engine (GKE). Il processo di questo codelab è il seguente:
- Scarica il progetto di base in Cloud Shell
- Creazione di microservizi in container
- Caricare container in Google Artifact Registry (GAR)
- esegui il deployment dei container in GKE
- Modifica il codice sorgente dei servizi per la strumentazione di traccia
- Vai al passaggio 2
Abilita Kubernetes Engine
Per prima cosa, abbiamo configurato un cluster Kubernetes in cui Shakesapp viene eseguito su GKE, quindi dobbiamo abilitare GKE. Vai al menu "Kubernetes Engine". e premi il pulsante ABILITA.
Ora è tutto pronto per creare un cluster Kubernetes.
Crea un cluster Kubernetes
Su Cloud Shell, esegui questo comando per creare un cluster Kubernetes. Verifica che il valore della zona si trovi al di sotto della regione che utilizzerai per la creazione del repository Artifact Registry. Modifica il valore della zona us-central1-f
se la regione del repository non copre la zona.
gcloud container clusters create otel-trace-codelab2 \ --zone us-central1-f \ --release-channel rapid \ --preemptible \ --enable-autoscaling \ --max-nodes 8 \ --no-enable-ip-alias \ --scopes cloud-platform
Output comando
Note: Your Pod address range (`--cluster-ipv4-cidr`) can accommodate at most 1008 node(s). Creating cluster otel-trace-codelab2 in us-central1-f... Cluster is being health-checked (master is healthy)...done. Created [https://container.googleapis.com/v1/projects/development-215403/zones/us-central1-f/clusters/otel-trace-codelab2]. To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/us-central1-f/otel-trace-codelab2?project=development-215403 kubeconfig entry generated for otel-trace-codelab2. NAME: otel-trace-codelab2 LOCATION: us-central1-f MASTER_VERSION: 1.23.6-gke.1501 MASTER_IP: 104.154.76.89 MACHINE_TYPE: e2-medium NODE_VERSION: 1.23.6-gke.1501 NUM_NODES: 3 STATUS: RUNNING
Configurazione di Artifact Registry e skaffold
Ora il cluster Kubernetes è pronto per il deployment. Poi ci prepariamo per un Container Registry per il push e il deployment dei container. Per questi passaggi, dobbiamo configurare un Artifact Registry (GAR) e uno skaffold per utilizzarlo.
Configurazione di Artifact Registry
Vai al menu di "Artifact Registry". e premi il pulsante ABILITA.
Dopo qualche istante, vedrai il browser del repository di GAR. Fai clic sul pulsante "CREA REPOSITORY" e inserisci il nome del repository.
In questo codelab, assegno il nome trace-codelab
al nuovo repository. Il formato dell'artefatto è "Docker" e il tipo di località è "Region". Scegli la regione vicina a quella impostata per la zona predefinita di Google Compute Engine. Ad esempio, per questo esempio è stato scelto "us-central1-f" in alto, quindi qui scegliamo "us-central1 (Iowa)". Poi fai clic sul pulsante "CREA" .
Ora vedi "trace-codelab" sul browser del repository.
Torneremo qui più tardi per controllare il percorso del registro.
Configurazione di Skaffold
Skaffold è uno strumento pratico per la creazione di microservizi in esecuzione su Kubernetes. Gestisce il flusso di lavoro di creazione, push e deployment di container di applicazioni con un piccolo insieme di comandi. Per impostazione predefinita, Skaffold utilizza Docker Registry come Container Registry, quindi devi configurare skaffold in modo che riconosca GAR al momento del push dei container.
Apri di nuovo Cloud Shell e verifica che skaffold sia installato. Cloud Shell installa skaffold nell'ambiente per impostazione predefinita. Esegui questo comando e visualizza la versione di skaffold.
skaffold version
Output comando
v1.38.0
Ora puoi registrare il repository predefinito per l'utilizzo di skaffold. Per ottenere il percorso del registro, vai alla dashboard di Artifact Registry e fai clic sul nome del repository che hai appena configurato nel passaggio precedente.
Nella parte superiore della pagina verranno visualizzate le tracce dei breadcrumb. Fai clic sull'icona per copiare il percorso del Registro di sistema negli appunti.
Facendo clic sul pulsante Copia, viene visualizzata la finestra di dialogo nella parte inferiore del browser con un messaggio simile al seguente:
"us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab" è stato copiato
Torna a Cloud Shell. Esegui il comando skaffold config set default-repo
con il valore che hai appena copiato dalla dashboard.
skaffold config set default-repo us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab
Output comando
set value default-repo to us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab for context gke_stackdriver-sandbox-3438851889_us-central1-b_stackdriver-sandbox
Inoltre, devi configurare il registro in base alla configurazione Docker. Esegui questo comando:
gcloud auth configure-docker us-central1-docker.pkg.dev --quiet
Output comando
{ "credHelpers": { "gcr.io": "gcloud", "us.gcr.io": "gcloud", "eu.gcr.io": "gcloud", "asia.gcr.io": "gcloud", "staging-k8s.gcr.io": "gcloud", "marketplace.gcr.io": "gcloud", "us-central1-docker.pkg.dev": "gcloud" } } Adding credentials for: us-central1-docker.pkg.dev
Ora puoi iniziare il passaggio successivo per configurare un container Kubernetes su GKE.
Riepilogo
In questo passaggio devi configurare il tuo ambiente codelab:
- Configura Cloud Shell
- Creazione di un repository Artifact Registry per il Container Registry
- Configurare skaffold per utilizzare Container Registry
- Creazione di un cluster Kubernetes in cui vengono eseguiti i microservizi del codelab
A seguire
Nel passaggio successivo, creerai, eseguirai il push e il deployment dei microservizi nel cluster
3. Crea ed esegui il push e il deployment dei microservizi
Scarica il materiale del codelab
Nel passaggio precedente, abbiamo configurato tutti i prerequisiti per questo codelab. Ora è tutto pronto per eseguire interi microservizi sopra i microservizi. Il materiale del codelab è ospitato su GitHub, quindi scaricalo nell'ambiente Cloud Shell con il seguente comando git.
cd ~ git clone https://github.com/ymotongpoo/opentelemetry-trace-codelab-go.git cd opentelemetry-trace-codelab-go
La struttura di directory del progetto è la seguente:
. ├── README.md ├── step0 │ ├── manifests │ ├── proto │ ├── skaffold.yaml │ └── src ├── step1 │ ├── manifests │ ├── proto │ ├── skaffold.yaml │ └── src ├── step2 │ ├── manifests │ ├── proto │ ├── skaffold.yaml │ └── src ├── step3 │ ├── manifests │ ├── proto │ ├── skaffold.yaml │ └── src ├── step4 │ ├── manifests │ ├── proto │ ├── skaffold.yaml │ └── src ├── step5 │ ├── manifests │ ├── proto │ ├── skaffold.yaml │ └── src └── step6 ├── manifests ├── proto ├── skaffold.yaml └── src
- manifest: i file manifest di Kubernetes
- proto: definizione proto per la comunicazione tra client e server
- src: directory per il codice sorgente di ciascun servizio
- skaffold.yaml: file di configurazione per skaffold
In questo codelab, aggiornerai il codice sorgente che si trova nella cartella step0
. Puoi anche fare riferimento al codice sorgente nelle cartelle step[1-6]
per le risposte nei passaggi seguenti. (La Parte 1 copre i passaggi da 0 a 4, mentre la Parte 2 copre i punti 5 e 6)
Esegui comando skaffold
Infine, sei pronto per creare, eseguire il push e il deployment di interi contenuti nel cluster Kubernetes che hai appena creato. Sembra che contenga più passaggi, ma quello effettivo è skaffold che fa tutto per te. Proviamo con questo comando:
cd step0 skaffold dev
Non appena esegui il comando, viene visualizzato l'output di log di docker build
e puoi confermare che il push è stato eseguito correttamente al registro.
Output comando
... ---> Running in c39b3ea8692b ---> 90932a583ab6 Successfully built 90932a583ab6 Successfully tagged us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/serverservice:step1 The push refers to repository [us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/serverservice] cc8f5a05df4a: Preparing 5bf719419ee2: Preparing 2901929ad341: Preparing 88d9943798ba: Preparing b0fdf826a39a: Preparing 3c9c1e0b1647: Preparing f3427ce9393d: Preparing 14a1ca976738: Preparing f3427ce9393d: Waiting 14a1ca976738: Waiting 3c9c1e0b1647: Waiting b0fdf826a39a: Layer already exists 88d9943798ba: Layer already exists f3427ce9393d: Layer already exists 3c9c1e0b1647: Layer already exists 14a1ca976738: Layer already exists 2901929ad341: Pushed 5bf719419ee2: Pushed cc8f5a05df4a: Pushed step1: digest: sha256:8acdbe3a453001f120fb22c11c4f6d64c2451347732f4f271d746c2e4d193bbe size: 2001
Dopo il push di tutti i container di servizio, i deployment di Kubernetes vengono avviati automaticamente.
Output comando
sha256:b71fce0a96cea08075dc20758ae561cf78c83ff656b04d211ffa00cedb77edf8 size: 1997 Tags used in deployment: - serverservice -> us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/serverservice:step4@sha256:8acdbe3a453001f120fb22c11c4f6d64c2451347732f4f271d746c2e4d193bbe - clientservice -> us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/clientservice:step4@sha256:b71fce0a96cea08075dc20758ae561cf78c83ff656b04d211ffa00cedb77edf8 - loadgen -> us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/loadgen:step4@sha256:eea2e5bc8463ecf886f958a86906cab896e9e2e380a0eb143deaeaca40f7888a Starting deploy... - deployment.apps/clientservice created - service/clientservice created - deployment.apps/loadgen created - deployment.apps/serverservice created - service/serverservice created
Dopo il deployment, vedrai i log effettivi dell'applicazione emessi nello stdout in ogni container, in questo modo:
Output comando
[client] 2022/07/14 06:33:15 {"match_count":3040} [loadgen] 2022/07/14 06:33:15 query 'love': matched 3040 [client] 2022/07/14 06:33:15 {"match_count":3040} [loadgen] 2022/07/14 06:33:15 query 'love': matched 3040 [client] 2022/07/14 06:33:16 {"match_count":3040} [loadgen] 2022/07/14 06:33:16 query 'love': matched 3040 [client] 2022/07/14 06:33:19 {"match_count":463} [loadgen] 2022/07/14 06:33:19 query 'tear': matched 463 [loadgen] 2022/07/14 06:33:20 query 'world': matched 728 [client] 2022/07/14 06:33:20 {"match_count":728} [client] 2022/07/14 06:33:22 {"match_count":463} [loadgen] 2022/07/14 06:33:22 query 'tear': matched 463
Tieni presente che, a questo punto, desideri visualizzare tutti i messaggi del server. Ok, finalmente puoi iniziare a dotare la tua applicazione di OpenTelemetry per il tracciamento distribuito dei servizi.
Prima di iniziare a utilizzare gli strumenti per il servizio, arresta il cluster con Ctrl-C.
Output comando
... [client] 2022/07/14 06:34:57 {"match_count":1} [loadgen] 2022/07/14 06:34:57 query 'what's past is prologue': matched 1 ^CCleaning up... - W0714 06:34:58.464305 28078 gcp.go:120] WARNING: the gcp auth plugin is deprecated in v1.22+, unavailable in v1.25+; use gcloud instead. - To learn more, consult https://cloud.google.com/blog/products/containers-kubernetes/kubectl-auth-changes-in-gke - deployment.apps "clientservice" deleted - service "clientservice" deleted - deployment.apps "loadgen" deleted - deployment.apps "serverservice" deleted - service "serverservice" deleted
Riepilogo
In questo passaggio, hai preparato il materiale del codelab nel tuo ambiente e hai confermato che skaffold funziona come previsto.
A seguire
Nel passaggio successivo modificherai il codice sorgente del servizio loadgen per instrumentare le informazioni di traccia.
4. Strumentazione per HTTP
Concetto di strumentazione e propagazione delle tracce
Prima di modificare il codice sorgente, vediamo brevemente come funzionano le tracce distribuite in un semplice diagramma.
In questo esempio, instruiamo il codice per esportare le informazioni di tracciamento e intervallo in Cloud Trace e propagare il contesto della traccia attraverso la richiesta dal servizio loadgen al servizio server.
Le applicazioni devono inviare metadati di traccia come ID traccia e ID intervallo per consentire a Cloud Trace di assemblare tutti gli intervalli con lo stesso ID traccia in un'unica traccia. Inoltre l'applicazione deve propagare i contesti di traccia (la combinazione di ID traccia e ID intervallo dell'intervallo padre) per richiedere i servizi downstream, in modo che possa essere a conoscenza del contesto di traccia che gestisce.
OpenTelemetry ti aiuta a:
- per generare un ID traccia e un ID intervallo univoci
- per esportare l'ID traccia e l'ID intervallo nel backend
- per propagare i contesti di traccia ad altri servizi
- per incorporare metadati aggiuntivi che aiutano ad analizzare le tracce
Componenti in OpenTelemetry Trace
Il processo per instrumentare la traccia dell'applicazione con OpenTelemetry è il seguente:
- Crea un esportatore
- Crea un'associazione TracerProvider per l'esportazione in 1 e impostala a livello globale.
- Imposta TextMapPropagaror per impostare il metodo di propagazione
- Recupera il Tracer da TracerProvider
- Genera un intervallo dalla traccia
Al momento, non è necessario conoscere le proprietà dettagliate di ogni componente, ma la cosa più importante da ricordare è:
- qui l'esportatore è collegabile a TracerProvider
- TracerProvider contiene tutte le configurazioni relative al campionamento e all'esportazione della traccia
- tutte le tracce sono raggruppate nell'oggetto Tracer
Comprendiamo meglio questo concetto, passiamo all'attività effettiva di programmazione.
Primo intervallo dello strumento
Servizio generatore di carico per strumentazione
Apri l'editor di Cloud Shell premendo il pulsante in alto a destra in Cloud Shell. Apri
step0/src/loadgen/main.go
da Explorer nel riquadro a sinistra e trova la funzione principale.
step0/src/loadgen/main.go
func main() { ... for range t.C { log.Printf("simulating client requests, round %d", i) if err := run(numWorkers, numConcurrency); err != nil { log.Printf("aborted round with error: %v", err) } log.Printf("simulated %d requests", numWorkers) if numRounds != 0 && i > numRounds { break } i++ } }
Nella funzione principale, vedi il loop che chiama la funzione run
al suo interno. Nell'implementazione corrente, la sezione contiene 2 righe di log che registrano l'inizio e la fine della chiamata di funzione. Ora strumentiamo le informazioni sull'intervallo per tracciare la latenza della chiamata di funzione.
Innanzitutto, come indicato nella sezione precedente, impostiamo tutte le configurazioni per OpenTelemetry. Aggiungi pacchetti OpenTelemetry come segue:
step0/src/loadgen/main.go
import ( "context" // step1. add packages "encoding/json" "fmt" "io" "log" "math/rand" "net/http" "net/url" "time" // step1. add packages "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/propagation" sdktrace "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.10.0" "go.opentelemetry.io/otel/trace" // step1. end add packages )
Per favorire la leggibilità, creiamo una funzione di configurazione denominata initTracer
e la chiamiamo nella funzione main
.
step0/src/loadgen/main.go
// step1. add OpenTelemetry initialization function func initTracer() (*sdktrace.TracerProvider, error) { // create a stdout exporter to show collected spans out to stdout. exporter, err := stdout.New(stdout.WithPrettyPrint()) if err != nil { return nil, err } // for the demonstration, we use AlwaysSmaple sampler to take all spans. // do not use this option in production. tp := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), ) otel.SetTracerProvider(tp) otel.SetTextMapPropagator(propagation.TraceContext{}) return tp, nil }
Potresti renderti conto che la procedura per configurare OpenTelemetry è quella descritta nella sezione precedente. In questa implementazione, utilizziamo un esportatore stdout
che esporta tutte le informazioni di traccia nello stdout in un formato strutturato.
Quindi la chiami dalla funzione principale. Chiama il initTracer()
e assicurati di chiamare il TracerProvider.Shutdown()
quando chiudi l'applicazione.
step0/src/loadgen/main.go
func main() { // step1. setup OpenTelemetry tp, err := initTracer() if err != nil { log.Fatalf("failed to initialize TracerProvider: %v", err) } defer func() { if err := tp.Shutdown(context.Background()); err != nil { log.Fatalf("error shutting down TracerProvider: %v", err) } }() // step1. end setup log.Printf("starting worder with %d workers in %d concurrency", numWorkers, numConcurrency) log.Printf("number of rounds: %d (0 is inifinite)", numRounds) ...
Una volta completata la configurazione, devi creare un intervallo con un ID traccia e un ID intervallo univoci. OpenTelemetry offre una pratica libreria. Aggiungi ulteriori nuovi pacchetti al client HTTP dello strumento.
step0/src/loadgen/main.go
import ( "context" "encoding/json" "fmt" "io" "log" "math/rand" "net/http" "net/http/httptrace" // step1. add packages "net/url" "time" // step1. add packages "go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" // step1. end add packages "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/propagation" sdktrace "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.10.0" "go.opentelemetry.io/otel/trace" )
Poiché il generatore di carico chiama il servizio client in HTTP con net/http
nella funzione runQuery
, utilizziamo il pacchetto Contributi per net/http
e abilitiamo la strumentazione con l'estensione del pacchetto httptrace
e otelhttp
.
Per prima cosa viene aggiunta una variabile globale del pacchetto httpClient per chiamare le richieste HTTP tramite il client instrumentato.
step0/src/loadgen/main.go
var httpClient = http.Client{ Transport: otelhttp.NewTransport(http.DefaultTransport) }
Poi aggiungi la strumentazione nella funzione runQuery
per creare l'intervallo personalizzato utilizzando OpenTelemetry e l'intervallo generato automaticamente dal client HTTP personalizzato. Procederai in questo modo:
- Ottieni un tracker da
TracerProvider
globale conotel.Tracer()
- Crea un intervallo principale con il metodo
Tracer.Start()
- Termina l'intervallo principale con una tempistica arbitraria (in questo caso, fine della funzione
runQuery
)
step0/src/loadgen/main.go
reqURL.RawQuery = v.Encode() // step1. replace http.Get() with custom client call // resp, err := http.Get(reqURL.String()) // step1. instrument trace ctx := context.Background() tr := otel.Tracer("loadgen") ctx, span := tr.Start(ctx, "query.request", trace.WithAttributes( semconv.TelemetrySDKLanguageGo, semconv.ServiceNameKey.String("loadgen.runQuery"), attribute.Key("query").String(s), )) defer span.End() ctx = httptrace.WithClientTrace(ctx, otelhttptrace.NewClientTrace(ctx)) req, err := http.NewRequestWithContext(ctx, "GET", reqURL.String(), nil) if err != nil { return -1, fmt.Errorf("error creating HTTP request object: %v", err) } resp, err := httpClient.Do(req) // step1. end instrumentation if err != nil { return -1, fmt.Errorf("error sending request to %v: %v", reqURL.String(), err) }
Ora hai terminato la strumentazione in loadgen (applicazione client HTTP). Assicurati di aggiornare go.mod
e go.sum
con il comando go mod
.
go mod tidy
Servizio clienti degli strumenti
Nella sezione precedente, abbiamo instrumentato la parte racchiusa nel rettangolo rosso nel disegno seguente. Abbiamo instrumentato le informazioni sugli intervalli nel servizio del generatore di carico. Analogamente al servizio generatore di carico, ora dobbiamo instrumentare il servizio client. La differenza dal servizio di generatore di carico è che il servizio client deve estrarre le informazioni sull'ID traccia propagate dal servizio generatore di carico nell'intestazione HTTP e utilizzare l'ID per generare intervalli.
Apri l'editor di Cloud Shell e aggiungi i pacchetti richiesti come abbiamo fatto per il servizio del generatore di carico.
step0/src/client/main.go
import ( "context" "encoding/json" "fmt" "io" "log" "net/http" "net/url" "os" "time" "opentelemetry-trace-codelab-go/client/shakesapp" // step1. add new import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/propagation" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/trace" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" // step1. end new import )
Dobbiamo ancora configurare OpenTelemtry. Basta copiare e incollare la funzione initTracer
da loadgen e chiamarla anche nella funzione main
del servizio client.
step0/src/client/main.go
// step1. add OpenTelemetry initialization function func initTracer() (*sdktrace.TracerProvider, error) { // create a stdout exporter to show collected spans out to stdout. exporter, err := stdout.New(stdout.WithPrettyPrint()) if err != nil { return nil, err } // for the demonstration, we use AlwaysSmaple sampler to take all spans. // do not use this option in production. tp := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), ) otel.SetTracerProvider(tp) otel.SetTextMapPropagator(propagation.TraceContext{}) return tp, nil }
È arrivato il momento di suonare gli strumenti. Poiché il servizio client deve accettare le richieste HTTP dal servizio loadgen, deve instrumentare il gestore. Il server HTTP nel servizio client è implementato con net/http e puoi utilizzare il pacchetto otelhttp
come abbiamo fatto nel loadgen.
Innanzitutto, sostituiamo la registrazione come gestore con il gestore otelhttp
. Nella funzione main
, trova le righe in cui è registrato il gestore HTTP con http.HandleFunc()
.
step0/src/client/main.go
// step1. change handler to intercept OpenTelemetry related headers // http.HandleFunc("/", svc.handler) otelHandler := otelhttp.NewHandler(http.HandlerFunc(svc.handler), "client.handler") http.Handle("/", otelHandler) // step1. end intercepter setting http.HandleFunc("/_genki", svc.health)
Quindi instruiamo lo span effettivo all'interno del gestore. Trova il gestore func (*clientService)() e aggiungi la strumentazione span con trace.SpanFromContext()
.
step0/src/client/main.go
func (cs *clientService) handler(w http.ResponseWriter, r *http.Request) { ... ctx := r.Context() ctx, cancel := context.WithCancel(ctx) defer cancel() // step1. instrument trace span := trace.SpanFromContext(ctx) defer span.End() // step1. end instrument ...
Con questa strumentazione, ottieni gli intervalli dall'inizio alla fine del metodo handler
. Per semplificare l'analisi degli intervalli, aggiungi un ulteriore attributo per archiviare il conteggio delle corrispondenze nella query. Subito prima della riga del log, aggiungi il seguente codice.
func (cs *clientService) handler(w http.ResponseWriter, r *http.Request) { ... // step1. add span specific attribute span.SetAttributes(attribute.Key("matched").Int64(resp.MatchCount)) // step1. end adding attribute log.Println(string(ret)) ...
Con tutti gli strumenti di cui sopra, hai completato la strumentazione di traccia tra loadgen e client. Vediamo come funziona. Esegui di nuovo il codice con skaffold.
skaffold dev
Dopo un po' di tempo per eseguire i servizi sul cluster GKE, vedrai l'enorme quantità di messaggi di log come questo:
Output comando
[loadgen] { [loadgen] "Name": "query.request", [loadgen] "SpanContext": { [loadgen] "TraceID": "cfa22247a542beeb55a3434392d46b89", [loadgen] "SpanID": "18b06404b10c418b", [loadgen] "TraceFlags": "01", [loadgen] "TraceState": "", [loadgen] "Remote": false [loadgen] }, [loadgen] "Parent": { [loadgen] "TraceID": "00000000000000000000000000000000", [loadgen] "SpanID": "0000000000000000", [loadgen] "TraceFlags": "00", [loadgen] "TraceState": "", [loadgen] "Remote": false [loadgen] }, [loadgen] "SpanKind": 1, [loadgen] "StartTime": "2022-07-14T13:13:36.686751087Z", [loadgen] "EndTime": "2022-07-14T13:14:31.849601964Z", [loadgen] "Attributes": [ [loadgen] { [loadgen] "Key": "telemetry.sdk.language", [loadgen] "Value": { [loadgen] "Type": "STRING", [loadgen] "Value": "go" [loadgen] } [loadgen] }, [loadgen] { [loadgen] "Key": "service.name", [loadgen] "Value": { [loadgen] "Type": "STRING", [loadgen] "Value": "loadgen.runQuery" [loadgen] } [loadgen] }, [loadgen] { [loadgen] "Key": "query", [loadgen] "Value": { [loadgen] "Type": "STRING", [loadgen] "Value": "faith" [loadgen] } [loadgen] } [loadgen] ], [loadgen] "Events": null, [loadgen] "Links": null, [loadgen] "Status": { [loadgen] "Code": "Unset", [loadgen] "Description": "" [loadgen] }, [loadgen] "DroppedAttributes": 0, [loadgen] "DroppedEvents": 0, [loadgen] "DroppedLinks": 0, [loadgen] "ChildSpanCount": 5, [loadgen] "Resource": [ [loadgen] { [loadgen] "Key": "service.name", [loadgen] "Value": { [loadgen] "Type": "STRING", [loadgen] "Value": "unknown_service:loadgen" ...
L'esportatore stdout
emette questi messaggi. Noterai che gli elementi padre di tutti gli intervalli per loadgen hanno TraceID: 00000000000000000000000000000000
, perché questo è l'intervallo principale, ovvero il primo intervallo nella traccia. Inoltre, noterai che l'attributo di incorporamento "query"
include la stringa di query che viene passata al servizio clienti.
Riepilogo
In questo passaggio, hai instrumentato il servizio generatore di carico e il servizio client che comunicano in HTTP e hai confermato di poter propagare correttamente il contesto di traccia tra i servizi ed esportare le informazioni sull'intervallo da entrambi i servizi allo stdout.
A seguire
Nel passaggio successivo, instrumenterai il servizio client e il servizio server per confermare come propagare il contesto di traccia tramite gRPC.
5. Strumentazione per gRPC
Nel passaggio precedente, abbiamo instrumentato la prima metà della richiesta in questo microservizio. In questo passaggio, cercheremo di instrumentare la comunicazione gRPC tra il servizio client e il servizio server. (Rettangolo verde e viola nella foto sotto)
Strumentazione di pre-creazione per client gRPC
L'ecosistema di OpenTelemetry offre molte librerie utili che aiutano gli sviluppatori a instrumentare le applicazioni. Nel passaggio precedente, abbiamo utilizzato la strumentazione precompilata per il pacchetto net/http
. In questo passaggio, poiché stiamo tentando di propagare il contesto della traccia tramite gRPC, utilizziamo la libreria apposito.
Innanzitutto, importi il pacchetto gRPC predefinito denominato otelgrpc
.
step0/src/client/main.go
import ( "context" "encoding/json" "fmt" "io" "log" "net/http" "net/url" "os" "time" "opentelemetry-trace-codelab-go/client/shakesapp" // step2. add prebuilt gRPC package (otelgrpc) "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/propagation" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/trace" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" )
Questa volta il servizio client è un client gRPC rispetto al servizio server, quindi devi instrumentare il client gRPC. Trova la funzione mustConnGRPC
e aggiungi intercettatori gRPC che analizzano i nuovi intervalli ogni volta che il client effettua richieste al server.
step0/src/client/main.go
// Helper function for gRPC connections: Dial and create client once, reuse. func mustConnGRPC(ctx context.Context, conn **grpc.ClientConn, addr string) { var err error // step2. add gRPC interceptor interceptorOpt := otelgrpc.WithTracerProvider(otel.GetTracerProvider()) *conn, err = grpc.DialContext(ctx, addr, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor(interceptorOpt)), grpc.WithStreamInterceptor(otelgrpc.StreamClientInterceptor(interceptorOpt)), grpc.WithTimeout(time.Second*3), ) // step2: end adding interceptor if err != nil { panic(fmt.Sprintf("Error %s grpc: failed to connect %s", err, addr)) } }
Poiché hai già configurato OpenTelemetry nella sezione precedente, non è necessario farlo.
Strumentazione predefinita per server gRPC
Come per il client gRPC, chiamiamo la strumentazione predefinita per il server gRPC. Aggiungi un nuovo pacchetto alla sezione di importazione, ad esempio:
step0/src/server/main.go
import ( "context" "fmt" "io/ioutil" "log" "net" "os" "regexp" "strings" "opentelemetry-trace-codelab-go/server/shakesapp" "cloud.google.com/go/storage" // step2. add OpenTelemetry packages including otelgrpc "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "go.opentelemetry.io/otel" stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/propagation" sdktrace "go.opentelemetry.io/otel/sdk/trace" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/grpc" healthpb "google.golang.org/grpc/health/grpc_health_v1" )
Poiché è la prima volta che strumenta il server, devi configurare prima OpenTelemetry, in modo simile a quanto abbiamo fatto per i servizi loadgen e client.
step0/src/server/main.go
// step2. add OpenTelemetry initialization function func initTracer() (*sdktrace.TracerProvider, error) { // create a stdout exporter to show collected spans out to stdout. exporter, err := stdout.New(stdout.WithPrettyPrint()) if err != nil { return nil, err } // for the demonstration, we use AlwaysSmaple sampler to take all spans. // do not use this option in production. tp := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), ) otel.SetTracerProvider(tp) otel.SetTextMapPropagator(propagation.TraceContext{}) return tp, nil } func main() { ... // step2. setup OpenTelemetry tp, err := initTracer() if err != nil { log.Fatalf("failed to initialize TracerProvider: %v", err) } defer func() { if err := tp.Shutdown(context.Background()); err != nil { log.Fatalf("error shutting down TracerProvider: %v", err) } }() // step2. end setup ...
Poi devi aggiungere degli intercetti server. Nella funzione main
, trova il luogo in cui viene chiamato grpc.NewServer()
e aggiungi intercettori alla funzione.
step0/src/server/main.go
func main() { ... svc := NewServerService() // step2: add interceptor interceptorOpt := otelgrpc.WithTracerProvider(otel.GetTracerProvider()) srv := grpc.NewServer( grpc.UnaryInterceptor(otelgrpc.UnaryServerInterceptor(interceptorOpt)), grpc.StreamInterceptor(otelgrpc.StreamServerInterceptor(interceptorOpt)), ) // step2: end adding interceptor shakesapp.RegisterShakespeareServiceServer(srv, svc) ...
Esegui il microservizio e conferma la traccia
Quindi esegui il codice modificato con il comando skaffold.
skaffold dev
Vediamo di nuovo una serie di informazioni sugli intervalli su stdout.
Output comando
... [server] { [server] "Name": "shakesapp.ShakespeareService/GetMatchCount", [server] "SpanContext": { [server] "TraceID": "89b472f213a400cf975e0a0041649667", [server] "SpanID": "96030dbad0061b3f", [server] "TraceFlags": "01", [server] "TraceState": "", [server] "Remote": false [server] }, [server] "Parent": { [server] "TraceID": "89b472f213a400cf975e0a0041649667", [server] "SpanID": "cd90cc3859b73890", [server] "TraceFlags": "01", [server] "TraceState": "", [server] "Remote": true [server] }, [server] "SpanKind": 2, [server] "StartTime": "2022-07-14T14:05:55.74822525Z", [server] "EndTime": "2022-07-14T14:06:03.449258891Z", [server] "Attributes": [ ... [server] ], [server] "Events": [ [server] { [server] "Name": "message", [server] "Attributes": [ ... [server] ], [server] "DroppedAttributeCount": 0, [server] "Time": "2022-07-14T14:05:55.748235489Z" [server] }, [server] { [server] "Name": "message", [server] "Attributes": [ ... [server] ], [server] "DroppedAttributeCount": 0, [server] "Time": "2022-07-14T14:06:03.449255889Z" [server] } [server] ], [server] "Links": null, [server] "Status": { [server] "Code": "Unset", [server] "Description": "" [server] }, [server] "DroppedAttributes": 0, [server] "DroppedEvents": 0, [server] "DroppedLinks": 0, [server] "ChildSpanCount": 0, [server] "Resource": [ [server] { ... [server] ], [server] "InstrumentationLibrary": { [server] "Name": "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc", [server] "Version": "semver:0.33.0", [server] "SchemaURL": "" [server] } [server] } ...
Ti accorgi che non hai incorporato alcun nome di intervallo e che hai creato manualmente intervalli con trace.Start()
o span.SpanFromContext()
. Ottieni comunque un numero elevato di intervalli perché gli intercetti gRPC li hanno generati.
Riepilogo
In questo passaggio, hai instrumentato la comunicazione basata su gRPC con il supporto delle librerie dell'ecosistema OpenTelemetry.
A seguire
Nel passaggio successivo, vedrai finalmente la traccia con Cloud Trace e imparerai ad analizzare gli intervalli raccolti.
6. Visualizza la traccia con Cloud Trace
Hai tracciato strumentato nell'intero sistema con OpenTelemetry. Finora hai imparato a instrumentare i servizi HTTP e gRPC. Anche se hai imparato a instrumentarli, non hai imparato ad analizzarli. In questa sezione, sostituirai gli esportatori stdout con gli esportatori Cloud Trace e imparerai ad analizzare le tracce.
Usa l'esportatore di Cloud Trace
Una delle caratteristiche più importanti di OpenTelemetry è la sua capacità di innesto dei cavi. Per visualizzare tutti gli intervalli raccolti dalla strumentazione, devi semplicemente sostituire l'esportatore stdout con quello di Cloud Trace.
Apri i file main.go
di ogni servizio e trova la funzione initTracer()
. Elimina la riga per generare un esportatore stdout e crea un esportatore di Cloud Trace.
step0/src/loadgen/main.go
import ( ... // step3. add OpenTelemetry for Cloud Trace package cloudtrace "github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace" ) // step1. add OpenTelemetry initialization function func initTracer() (*sdktrace.TracerProvider, error) { // step3. replace stdout exporter with Cloud Trace exporter // cloudtrace.New() finds the credentials to Cloud Trace automatically following the // rules defined by golang.org/x/oauth2/google.findDefaultCredentailsWithParams. // https://pkg.go.dev/golang.org/x/oauth2/google#FindDefaultCredentialsWithParams exporter, err := cloudtrace.New() // step3. end replacing exporter if err != nil { return nil, err } // for the demonstration, we use AlwaysSmaple sampler to take all spans. // do not use this option in production. tp := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), ) otel.SetTracerProvider(tp) otel.SetTextMapPropagator(propagation.TraceContext{}) return tp, nil }
Devi modificare la stessa funzione anche nel servizio client e server.
Esegui il microservizio e conferma la traccia
Dopo la modifica, esegui il cluster come di consueto con il comando skaffold.
skaffold dev
A questo punto, su stdout non vengono visualizzate molte informazioni sugli intervalli nel formato dei log strutturati, in quanto hai sostituito l'esportatore con uno di Cloud Trace.
Output comando
[loadgen] 2022/07/14 15:01:07 simulated 20 requests [loadgen] 2022/07/14 15:01:07 simulating client requests, round 37 [loadgen] 2022/07/14 15:01:14 query 'sweet': matched 958 [client] 2022/07/14 15:01:14 {"match_count":958} [client] 2022/07/14 15:01:14 {"match_count":3040} [loadgen] 2022/07/14 15:01:14 query 'love': matched 3040 [client] 2022/07/14 15:01:15 {"match_count":349} [loadgen] 2022/07/14 15:01:15 query 'hello': matched 349 [client] 2022/07/14 15:01:15 {"match_count":484} [loadgen] 2022/07/14 15:01:15 query 'faith': matched 484 [loadgen] 2022/07/14 15:01:15 query 'insolence': matched 14 [client] 2022/07/14 15:01:15 {"match_count":14} [client] 2022/07/14 15:01:21 {"match_count":484} [loadgen] 2022/07/14 15:01:21 query 'faith': matched 484 [client] 2022/07/14 15:01:21 {"match_count":728} [loadgen] 2022/07/14 15:01:21 query 'world': matched 728 [client] 2022/07/14 15:01:22 {"match_count":484} [loadgen] 2022/07/14 15:01:22 query 'faith': matched 484 [loadgen] 2022/07/14 15:01:22 query 'hello': matched 349 [client] 2022/07/14 15:01:22 {"match_count":349} [client] 2022/07/14 15:01:23 {"match_count":1036} [loadgen] 2022/07/14 15:01:23 query 'friend': matched 1036 [loadgen] 2022/07/14 15:01:28 query 'tear': matched 463 ...
Ora verifichiamo che tutti gli intervalli vengano inviati correttamente a Cloud Trace. Accedi alla console Cloud e vai a "Elenco di tracce". È facile accedervi dalla casella di ricerca. In caso contrario, puoi fare clic sul menu nel riquadro a sinistra.
Quindi noterai che molte macchie blu sono distribuite nel grafico della latenza. Ogni spot rappresenta una singola traccia.
Fai clic su una di queste per visualizzare i dettagli all'interno della traccia.
Anche da questa semplice occhiata veloce, conosci già molti dati. Ad esempio, dal grafico a cascata, puoi notare che la causa della latenza è principalmente dell'intervallo denominato shakesapp.ShakespeareService/GetMatchCount
. (Vedi 1 nell'immagine sopra) Puoi confermarlo dalla tabella di riepilogo. La colonna più a destra mostra la durata di ogni intervallo. Inoltre, questa traccia riguardava la query "friend". (vedi 2 nell'immagine qui sopra)
Date queste brevi analisi, potresti capire che hai bisogno di conoscere intervalli più granulari all'interno del metodo GetMatchCount
. Rispetto alle informazioni stdout, la visualizzazione è potente. Per saperne di più sui dettagli di Cloud Trace, consulta la nostra documentazione ufficiale.
Riepilogo
In questo passaggio, hai sostituito l'esportatore stdout con uno di Cloud Trace e hai visualizzato le tracce su Cloud Trace. Hai anche imparato ad analizzare le tracce.
A seguire
Nel passaggio successivo modificherai il codice sorgente del servizio server per aggiungere un intervallo secondario in GetMatchCount.
7. Aggiungi intervallo secondario per migliorare l'analisi
Nel passaggio precedente, hai scoperto che la causa del tempo di round trip osservato da loadgen è principalmente il processo all'interno del metodo GetMatchCount, il gestore gRPC, nel servizio server. Tuttavia, poiché non abbiamo utilizzato strumenti diversi dal gestore, non siamo in grado di ottenere ulteriori informazioni dal grafico a cascata. Questo è un caso comune quando iniziamo a utilizzare gli strumenti per i microservizi.
In questa sezione, indicheremo un intervallo secondario in cui il server chiama Google Cloud Storage, perché è comune quando un I/O di rete esterna richiede molto tempo ed è importante identificare se la causa è la chiamata.
Instrumenta un intervallo secondario nel server
Apri main.go
nel server e trova la funzione readFiles
. Questa funzione chiama una richiesta a Google Cloud Storage per recuperare tutti i file di testo delle opere di Shakespeare. In questa funzione, puoi creare un intervallo secondario, come hai fatto per la strumentazione server HTTP nel servizio client.
step0/src/server/main.go
func readFiles(ctx context.Context, bucketName, prefix string) ([]string, error) { type resp struct { s string err error } // step4: add an extra span span := trace.SpanFromContext(ctx) span.SetName("server.readFiles") span.SetAttributes(attribute.Key("bucketname").String(bucketName)) defer span.End() // step4: end add span ...
E questo è tutto per l'aggiunta di un nuovo intervallo. Vediamo come funziona eseguendo l'app.
Esegui il microservizio e conferma la traccia
Dopo la modifica, esegui il cluster come di consueto con il comando skaffold.
skaffold dev
E scegli una traccia denominata query.request
dall'elenco di tracce. Vedrai un grafico a cascata a traccia simile, tranne per un nuovo intervallo sotto shakesapp.ShakespeareService/GetMatchCount
. (L'intervallo racchiuso dal rettangolo rosso sottostante)
Ora si può capire da questo grafico che la chiamata esterna a Google Cloud Storage occupa una grande quantità di latenza, ma la maggior parte della latenza viene generata da altri fattori.
Hai già ottenuto molti insight solo da un paio di osservazioni dal grafico a cascata di Tracce. Come ottieni gli ulteriori dettagli sulle prestazioni della tua applicazione? Qui interviene il profiler, ma per il momento andiamo alla fine di questo codelab e deleghiamo tutti i tutorial di profiler alla parte 2.
Riepilogo
In questo passaggio, hai instrumentato un altro intervallo nel servizio server e hai ottenuto ulteriori insight sulla latenza del sistema.
8. Complimenti
Hai creato tracce distribuite con OpenTelemery e hai confermato le latenze delle richieste nel microservizio su Google Cloud Trace.
Per esercizi estesi, puoi provare autonomamente i seguenti argomenti.
- L'implementazione attuale invia tutti gli intervalli generati dal controllo di integrità. (
grpc.health.v1.Health/Check
) Come si filtrano questi intervalli da Cloud Traces? Il suggerimento è qui. - Correla i log eventi con gli intervalli e osserva come funziona su Google Cloud Trace e Google Cloud Logging. Il suggerimento è qui.
- Sostituisci qualche servizio con quello in un'altra lingua e prova a instrumentarlo con OpenTelemetry per quella lingua.
Inoltre, se dopo questo passaggio vuoi saperne di più sul profiler, passa alla parte 2. In questo caso, puoi saltare la sezione dedicata alla pulizia.
Pulizia
Dopo questo codelab, arresta il cluster Kubernetes e assicurati di eliminare il progetto in modo da non ricevere addebiti imprevisti su Google Kubernetes Engine, Google Cloud Trace e Google Artifact Registry.
Elimina innanzitutto il cluster. Se esegui il cluster con skaffold dev
, devi solo premere Ctrl-C. Se esegui il cluster con skaffold run
, esegui questo comando:
skaffold delete
Output comando
Cleaning up... - deployment.apps "clientservice" deleted - service "clientservice" deleted - deployment.apps "loadgen" deleted - deployment.apps "serverservice" deleted - service "serverservice" deleted
Dopo aver eliminato il cluster, nel riquadro di menu seleziona "IAM e Amministratore" > "Impostazioni", quindi fai clic su "SPEGNI" .
Quindi inserisci l'ID progetto (non il nome del progetto) nel modulo della finestra di dialogo e conferma l'arresto.