1. Introdução
Última atualização:15/07/2022
Observabilidade do aplicativo
Observabilidade e OpenTelemetry
Observabilidade é o termo usado para descrever um atributo de um sistema. Um sistema com observabilidade permite que as equipes depurem ativamente o sistema. Nesse contexto, três pilares da observabilidade: registros, métricas e traces são a instrumentação fundamental para que o sistema adquira observabilidade.
O OpenTelemetry é um conjunto de especificações, bibliotecas e agentes que aceleram a instrumentação e a exportação de dados de telemetria (registros, métricas e traces) exigidos pela observabilidade. O OpenTelemetry é um projeto de padrão aberto conduzido pela comunidade pela CNCF. Ao utilizar bibliotecas que o projeto e seu ecossistema fornecem, os desenvolvedores são capazes de instrumentar seus aplicativos de maneira neutra em termos de fornecedor e contra várias arquiteturas.
Além dos três pilares da observabilidade, a criação de perfil contínua é outro componente principal para observabilidade e está expandindo a base de usuários no setor. O Cloud Profiler é um dos criadores e fornece uma interface fácil para detalhar as métricas de desempenho nas pilhas de chamadas do aplicativo.
Este codelab é a primeira parte da série e aborda a instrumentação de traces distribuídos em microsserviços com o OpenTelemetry e o Cloud Trace. A parte 2 aborda a criação de perfil contínua com o Cloud Profiler.
Rastreamento distribuído
Entre registros, métricas e traces, o trace é a telemetria que informa a latência de uma parte específica do processo no sistema. Especialmente na era dos microsserviços, o trace distribuído é o forte impulsionador para descobrir gargalos de latência no sistema distribuído em geral.
Ao analisar traces distribuídos, a visualização de dados de rastreamento é a chave para entender rapidamente as latências gerais do sistema. No trace distribuído, processamos um conjunto de chamadas para processar uma única solicitação para o ponto de entrada do sistema em uma forma de trace que contém vários períodos.
O período representa uma unidade de trabalho realizada em um sistema distribuído, registrando os horários de início e término. Os períodos geralmente têm relações hierárquicas entre si. Na imagem abaixo de todos os períodos menores, estão os períodos filhos de um período /messages grande e reunidos em um trace que mostra o caminho do trabalho em um sistema.
O Google Cloud Trace é uma das opções de back-end de trace distribuído e é bem integrado a outros produtos do Google Cloud.
O que você vai criar
Neste codelab, você vai instrumentar informações de rastreamento nos serviços chamados de "aplicativo Shakespeare". (conhecido como Shakesapp) executado em um cluster do Google Kubernetes Engine. A arquitetura do Shakesapp é descrita abaixo:
- O Loadgen envia uma string de consulta ao cliente em HTTP
- Os clientes passam a consulta do loadgen para o servidor no gRPC
- O servidor aceita a consulta do cliente, busca todos os trabalhos do Shakespare em formato de texto no Google Cloud Storage, pesquisa as linhas que contêm a consulta e retorna o número da linha correspondente ao cliente
Você instrumentará as informações de rastreamento em toda a solicitação. Depois disso, você vai incorporar um agente do criador de perfil no servidor e investigar o gargalo.
O que você vai aprender
- Como começar a usar as bibliotecas do Trace do OpenTelemetry no projeto Go
- Como criar um período com a biblioteca
- Como propagar contextos de período entre os componentes do app
- Como enviar dados de trace para o Cloud Trace
- Como analisar o trace no Cloud Trace
Este codelab explica como instrumentar seus microsserviços. Para facilitar a compreensão, este exemplo contém apenas três componentes (gerador de carga, cliente e servidor). No entanto, é possível aplicar o mesmo processo explicado neste codelab em sistemas grandes e mais complexos.
O que é necessário
- Conhecimento básico em Go.
- Noções básicas do Kubernetes.
2. Configuração e requisitos
Configuração de ambiente autoguiada
Se você ainda não tem uma Conta do Google (Gmail ou Google Apps), crie uma. Faça login no Console do Google Cloud Platform ( console.cloud.google.com) e crie um novo projeto.
Se você já tiver um projeto, clique no menu suspenso de seleção no canto superior esquerdo do console:
e clique no botão "NEW PROJECT" na caixa de diálogo exibida para criar um novo projeto:
Se você ainda não tiver um projeto, uma caixa de diálogo como esta será exibida para criar seu primeiro:
A caixa de diálogo de criação de projeto subsequente permite que você insira os detalhes do novo projeto:
Lembre-se do código do projeto, um nome exclusivo em todos os projetos do Google Cloud. O nome acima já foi escolhido e não servirá para você. Faremos referência a ele mais adiante neste codelab como PROJECT_ID.
Em seguida, você precisará ativar o faturamento no Developers Console para usar os recursos do Google Cloud e ativar a API Cloud Trace, caso ainda não tenha feito isso.
A execução por meio deste codelab terá um custo baixo, mas poderá ser mais se você decidir usar mais recursos ou se deixá-los em execução. Consulte a seção "limpeza" no final deste documento. Os preços do Google Cloud Trace, do Google Kubernetes Engine e do Google Artifact Registry estão indicados na documentação oficial.
- Preços do pacote de operações do Google Cloud | Pacote de operações
- Preços | Documentação do Kubernetes Engine
- Preços do Artifact Registry | Documentação do Artifact Registry
Novos usuários do Google Cloud Platform estão qualificados para uma avaliação gratuita de US$ 300, o que torna este codelab totalmente gratuito.
Configuração do Google Cloud Shell
Embora o Google Cloud e o Google Cloud Trace possam ser operados remotamente do seu laptop, neste codelab vamos usar o Google Cloud Shell, um ambiente de linha de comando executado no Cloud.
O Cloud Shell é uma máquina virtual com base em Debian que contém todas as ferramentas de desenvolvimento necessárias. Ela oferece um diretório principal persistente de 5 GB, além de ser executada no Google Cloud. Isso aprimora o desempenho e a autenticação da rede. Isso significa que tudo que você precisa para este codelab é um navegador (sim, funciona em um Chromebook).
Para ativar o Cloud Shell no Console do Cloud, basta clicar em Ativar o Cloud Shell . O provisionamento e a conexão ao ambiente devem levar apenas alguns instantes.
Depois de se conectar ao Cloud Shell, você já estará autenticado e o projeto estará configurado com seu PROJECT_ID
.
gcloud auth list
Resposta ao comando
Credentialed accounts: - <myaccount>@<mydomain>.com (active)
gcloud config list project
Resposta ao comando
[core] project = <PROJECT_ID>
Se, por algum motivo, o projeto não estiver definido, basta emitir o seguinte comando:
gcloud config set project <PROJECT_ID>
Quer encontrar seu PROJECT_ID
? Veja qual ID você usou nas etapas de configuração ou procure-o no painel do Console do Cloud:
O Cloud Shell também define algumas variáveis de ambiente por padrão, o que pode ser útil ao executar comandos futuros.
echo $GOOGLE_CLOUD_PROJECT
Resposta ao comando
<PROJECT_ID>
Defina a zona padrão e a configuração do projeto:
gcloud config set compute/zone us-central1-f
É possível escolher uma variedade de zonas diferentes. Para mais informações, consulte Regiões e zonas.
Configuração de idioma do Go
Neste codelab, usamos Go para todo o código-fonte. Execute o comando a seguir no Cloud Shell e confirme se a versão do Go é 1.17 ou mais recente.
go version
Resposta ao comando
go version go1.18.3 linux/amd64
Configurar um cluster do Google Kubernetes
Neste codelab, você executará um cluster de microsserviços no Google Kubernetes Engine (GKE). O processo deste codelab é o seguinte:
- Faça o download do projeto de referência no Cloud Shell
- Crie microsserviços em contêineres
- Fazer upload de contêineres no Google Artifact Registry (GAR)
- Implantar contêineres no GKE
- Modificar o código-fonte dos serviços para instrumentação de rastreamento
- Ir para a etapa 2
Ativar o Kubernetes Engine
Primeiro, configuramos um cluster do Kubernetes em que o Shakesapp é executado no GKE, portanto, precisamos ativar o GKE. Acesse o menu "Kubernetes Engine". e pressione o botão ATIVAR.
Agora você já pode criar um cluster do Kubernetes.
Crie o cluster do Kubernetes
No Cloud Shell, execute o comando a seguir para criar um cluster do Kubernetes. Confirme se o valor da zona está na região que você vai usar para criar o repositório do Artifact Registry. Altere o valor da zona us-central1-f
se a região do repositório não cobrir a 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
Resposta ao 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
Configuração do Artifact Registry e do skaffold
Agora temos um cluster do Kubernetes pronto para implantação. Em seguida, preparamos um Container Registry para enviar e implantar contêineres. Para estas etapas, precisamos configurar um Artifact Registry (GAR) e skaffold para usá-lo.
Configuração do Artifact Registry
Navegue até o menu do "Artifact Registry". e pressione o botão ATIVAR.
Depois de alguns instantes, você verá o navegador do repositório do GAR. Clique em "CRIAR REPOSITÓRIO". e insira o nome do repositório.
Neste codelab, nomeio o novo repositório como trace-codelab
. O formato do artefato é "Docker" e o tipo é "Região". Escolha a região próxima àquela que você definiu para a zona padrão do Google Compute Engine. Por exemplo, este exemplo escolhe "us-central1-f" acima, então aqui escolhemos "us-central1 (Iowa)". Em seguida, clique no botão "CRIAR" .
Agora você vai encontrar o "trace-codelab" no navegador do repositório.
Vamos voltar aqui mais tarde para verificar o caminho do registro.
Configuração do Skaffold
O Skaffold é uma ferramenta útil para a criação de microsserviços executados no Kubernetes. Ele lida com o fluxo de trabalho de criação, envio e implantação de contêineres de aplicativos com um pequeno conjunto de comandos. Por padrão, o Skaffold usa o Docker Registry como registro de contêiner. Portanto, é necessário configurar o skaffold para reconhecer o GAR ao enviar contêineres para ele.
Abra o Cloud Shell novamente e confirme se o skaffold está instalado. O Cloud Shell instala o skaffold no ambiente por padrão. Execute o comando a seguir e confira a versão do skaffold.
skaffold version
Resposta ao comando
v1.38.0
Agora, você pode registrar o repositório padrão para o skaffold usar. Para encontrar o caminho do registro, acesse o painel do Artifact Registry e clique no nome do repositório que você configurou na etapa anterior.
Em seguida, você verá trilhas de navegação estrutural na parte superior da página. Clique no ícone para copiar o caminho do registro para a área de transferência.
Ao clicar no botão "Copiar", você vê a caixa de diálogo na parte inferior do navegador com a seguinte mensagem:
"us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab" foi copiado
Volte para o Cloud Shell. Execute o comando skaffold config set default-repo
com o valor que você acabou de copiar do painel.
skaffold config set default-repo us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab
Resposta ao 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
Além disso, você precisa configurar o registro para o Docker. Execute este comando:
gcloud auth configure-docker us-central1-docker.pkg.dev --quiet
Resposta ao 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
Agora está tudo pronto para a próxima etapa de configuração de um contêiner do Kubernetes no GKE.
Resumo
Nesta etapa, você vai configurar seu ambiente do codelab:
- Configurar o Cloud Shell
- Criou um repositório do Artifact Registry para o Container Registry
- Configurar o skaffold para usar o Container Registry
- Criou um cluster do Kubernetes em que os microsserviços do codelab são executados
A seguir
Na próxima etapa, você vai criar, enviar e implantar seus microsserviços no cluster
3. Criar, transferir e implantar os microsserviços
Faça o download do material do codelab
Na etapa anterior, configuramos todos os pré-requisitos para este codelab. Agora está tudo pronto para executar microsserviços inteiros neles. O material do codelab está hospedado no GitHub. Faça o download dele para o ambiente do Cloud Shell com o comando git abaixo.
cd ~ git clone https://github.com/ymotongpoo/opentelemetry-trace-codelab-go.git cd opentelemetry-trace-codelab-go
A estrutura de diretórios do projeto é a seguinte:
. ├── 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
- manifestos: arquivos de manifesto do Kubernetes
- proto: definição proto para a comunicação entre cliente e servidor
- src: diretórios para o código-fonte de cada serviço
- skaffold.yaml: arquivo de configuração do skaffold
Neste codelab, você atualizará o código-fonte localizado na pasta step0
. Você também pode consultar o código-fonte em pastas step[1-6]
para ver as respostas nas etapas a seguir. (A Parte 1 abrange as etapas 0 a 4, e a Parte 2 abrange as etapas 5 e 6)
Executar o comando skaffold
Por fim, você já pode criar, enviar e implantar todo o conteúdo no cluster do Kubernetes que acabou de criar. Parece que tem várias etapas, mas o skaffold na verdade faz tudo por você. Vamos tentar fazer isso com o seguinte comando:
cd step0 skaffold dev
Assim que executar o comando, você verá a saída do registro de docker build
e poderá confirmar que eles foram enviados com sucesso para o registro.
Resposta ao 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
Após o envio de todos os contêineres de serviço, as implantações do Kubernetes são iniciadas automaticamente.
Resposta ao 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
Após a implantação, os registros do aplicativo serão emitidos para stdout em cada contêiner, da seguinte forma:
Resposta ao 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
Observe que, neste momento, você quer ver todas as mensagens do servidor. Agora está tudo pronto para começar a instrumentar seu aplicativo com o OpenTelemetry para o rastreamento distribuído dos serviços.
Antes de começar a instrumentar o serviço, encerre seu cluster com Ctrl-C.
Resposta ao 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
Resumo
Nesta etapa, você preparou o material do codelab no seu ambiente e confirmou as execuções do skaffold conforme o esperado.
A seguir
Na próxima etapa, você vai modificar o código-fonte do serviço loadgen para instrumentar as informações de rastreamento.
4. Instrumentação para HTTP
Conceito de instrumentação e propagação de rastreamento
Antes de editar o código-fonte, deixe-me explicar brevemente como os traces distribuídos funcionam em um diagrama simples.
Neste exemplo, instrumentamos o código para exportar informações do Trace e do período para o Cloud Trace e propagar o contexto do trace na solicitação do serviço loadgen para o serviço de servidor.
Os aplicativos precisam enviar metadados de traces, como ID do trace e ID do período, para que o Cloud Trace monte todos os períodos que tenham o mesmo ID do Trace em um único trace. Além disso, o aplicativo precisa propagar contextos de trace (a combinação de ID de trace e ID de período do período pai) ao solicitar serviços downstream. Assim, ele pode estar ciente do contexto de trace que está processando.
O OpenTelemetry ajuda você a:
- para gerar um ID de trace e um ID de período exclusivos
- para exportar o ID do Trace e o ID do período para o back-end
- para propagar contextos de trace para outros serviços
- para incorporar metadados extras que ajudam a analisar rastros
Componentes no Trace do OpenTelemetry
O processo para instrumentar o rastreamento do aplicativo com o OpenTelemetry é o seguinte:
- Criar um exportador
- Crie um TracerProvider vinculando o exportador em 1 e o defina como global.
- Definir TextMapPropagaror para definir o método de propagação
- Acessar o Tracer do TracerProvider
- Gerar período do rastreador
A partir de agora, você não precisa entender as propriedades detalhadas de cada componente, mas o mais importante a ser lembrado é:
- o exportador aqui é conectável ao TracerProvider
- O TracerProvider mantém todas as configurações relacionadas à amostragem e à exportação de traces
- todos os traces são agrupados no objeto Tracer
Depois de entender isso, vamos passar para o trabalho de programação.
Primeiro período da instrumentação
Serviço gerador de carga por instrumento
Pressione o botão no canto superior direito para abrir o Editor do Cloud Shell. Abra step0/src/loadgen/main.go
no explorador no painel esquerdo e encontre a função principal.
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++ } }
Na função principal, a repetição chama a função run
. Na implementação atual, a seção tem duas linhas de registro que registram o início e o fim da chamada de função. Agora, vamos instrumentar as informações de período para rastrear a latência da chamada de função.
Primeiro, conforme observado na seção anterior, vamos definir todas as configurações do OpenTelemetry. Adicione os pacotes do OpenTelemetry da seguinte maneira:
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 )
Para facilitar a leitura, criamos uma função de configuração com o nome initTracer
e a chamamos na função 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 }
Talvez você perceba que o procedimento para configurar o OpenTelemetry é o descrito na seção anterior. Nesta implementação, usamos um exportador stdout
que exporta todas as informações de trace para o stdout em um formato estruturado.
Em seguida, você faz a chamada pela função main. Chame initTracer()
e chame TracerProvider.Shutdown()
quando fechar o aplicativo.
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) ...
Depois de concluir a configuração, é necessário criar um período com um ID de trace e um ID de período exclusivos. O OpenTelemetry oferece uma biblioteca útil para isso. Adicione novos pacotes ao cliente HTTP do instrumento.
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" )
Como o gerador de carga está chamando o serviço do cliente em HTTP com net/http
na função runQuery
, usamos o pacote de contribuição para net/http
e ativamos a instrumentação com a extensão dos pacotes httptrace
e otelhttp
.
Primeiro, adicione uma variável global httpClient do pacote para chamar solicitações HTTP por meio do cliente instrumentado.
step0/src/loadgen/main.go
var httpClient = http.Client{ Transport: otelhttp.NewTransport(http.DefaultTransport) }
Em seguida, adicione instrumentação na função runQuery
para criar o período personalizado usando o OpenTelemetry e o período gerado automaticamente pelo cliente HTTP personalizado. Você vai fazer o seguinte:
- Acessar um Tracer de
TracerProvider
global comotel.Tracer()
- Criar um período raiz com o método
Tracer.Start()
- Finalizar o período raiz em um tempo arbitrário (neste caso, o fim da função
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) }
Você terminou a instrumentação no loadgen (aplicativo cliente HTTP). Atualize go.mod
e go.sum
com o comando go mod
.
go mod tidy
Serviço de cliente de instrumentos
Na seção anterior, instrumentamos a parte envolvida no retângulo vermelho no desenho abaixo. Instrumentamos as informações de período no serviço de gerador de carga. Da mesma forma que o serviço de gerador de carga, agora precisamos instrumentar o serviço ao cliente. A diferença do serviço de gerador de carga é que o serviço cliente precisa extrair as informações do ID de trace propagado desse serviço no cabeçalho HTTP e usar o ID para gerar períodos.
Abra o editor do Cloud Shell e adicione os pacotes necessários, como fizemos para o serviço de gerador de carga.
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 )
Novamente, precisamos configurar o OpenTelemtry. Basta copiar e colar a função initTracer
do loadgen e chamá-la na função main
do serviço do cliente também.
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 }
Agora é hora de instrumentar os períodos. Como o serviço do cliente precisa aceitar solicitações HTTP do serviço loadgen, ele precisa instrumentar o gerenciador. O servidor HTTP no serviço do cliente é implementado com net/http, e é possível usar o pacote otelhttp
como fizemos no loadgen.
Primeiro, substituímos o registro do gerenciador pelo gerenciador otelhttp
. Na função main
, encontre as linhas em que o gerenciador HTTP está registrado com 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)
Em seguida, instrumentamos o período real dentro do gerenciador. Encontre a função (*clientService) handle() e adicione a instrumentação de período com 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 ...
Com essa instrumentação, você consegue os períodos do início ao fim do método handler
. Para facilitar a análise dos períodos, adicione um atributo extra que armazene a contagem correspondente à consulta. Logo antes da linha de registro, adicione o código a seguir.
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)) ...
Com toda a instrumentação acima, você concluiu a instrumentação de rastreamento entre o loadgen e o cliente. Como ele funciona. Execute o código com o skaffold novamente.
skaffold dev
Depois de um tempo para executar os serviços no cluster do GKE, você vai notar uma grande quantidade de mensagens de registro como esta:
Resposta ao 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" ...
O exportador stdout
emite essas mensagens. Você vai notar que os pais de todos os períodos por loadgen têm TraceID: 00000000000000000000000000000000
, porque esse é o período raiz, ou seja, o primeiro no trace. Além disso, você descobre que o atributo de incorporação "query"
tem a string de consulta que é transmitida ao serviço ao cliente.
Resumo
Nesta etapa, você instrumentou o serviço de gerador de carga e o serviço de cliente que se comunicam em HTTP e confirmou que é possível propagar com êxito o contexto do Trace entre os serviços e exportar as informações do período de ambos os serviços para o stdout.
A seguir
Na próxima etapa, você vai instrumentar o serviço de cliente e o serviço de servidor para confirmar como propagar o contexto de trace via gRPC.
5. Instrumentação para gRPC
Na etapa anterior, instrumentamos a primeira metade da solicitação nesses microsserviços. Nesta etapa, tentamos instrumentar a comunicação do gRPC entre o serviço do cliente e o serviço do servidor. (retângulo verde e roxo na imagem abaixo)
Instrumentação de pré-criação para cliente gRPC
O ecossistema do OpenTelemetry oferece muitas bibliotecas úteis que ajudam os desenvolvedores a instrumentar aplicativos. Na etapa anterior, usamos a instrumentação pré-criada para o pacote net/http
. Nesta etapa, como estamos tentando propagar o contexto do Trace pelo gRPC, usamos a biblioteca para isso.
Primeiro, importe o pacote gRPC pré-criado chamado 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" )
Desta vez, o serviço do cliente é um cliente gRPC em relação ao serviço do servidor, portanto, você precisa instrumentar o cliente gRPC. Encontre a função mustConnGRPC
e adicione interceptadores gRPC que instrumentem novos períodos sempre que o cliente faz solicitações ao servidor.
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)) } }
Como você já configurou o OpenTelemetry na seção anterior, não é necessário fazer isso.
Instrumentação pré-criada para o servidor gRPC
Assim como fizemos com o cliente gRPC, chamamos a instrumentação pré-criada para o servidor gRPC. Adicione o novo pacote à seção de importação da seguinte forma:
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" )
Como esta é a primeira vez que você instrumenta o servidor, é preciso configurar o OpenTelemetry primeiro, assim como fizemos com o loadgen e os serviços de cliente.
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 ...
Em seguida, você precisa adicionar interceptadores de servidores. Na função main
, encontre o lugar em que grpc.NewServer()
é chamado e adicione interceptadores à função.
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) ...
Executar o microsserviço e confirmar o trace
Em seguida, execute o código modificado com o comando skaffold.
skaffold dev
Agora, você verá várias informações de períodos em stdout.
Resposta ao 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] } ...
Você percebe que não incorporou nenhum nome de período e criou períodos manualmente com trace.Start()
ou span.SpanFromContext()
. Ainda assim, você recebe um grande número de períodos porque eles foram gerados pelos interceptadores gRPC.
Resumo
Nesta etapa, você instrumentou a comunicação baseada em gRPC com o suporte das bibliotecas do ecossistema do OpenTelemetry.
A seguir
Na próxima etapa, você verá por fim a visualização do trace com o Cloud Trace e aprenderá a analisar os períodos coletados.
6. Visualizar traces com o Cloud Trace
Você instrumentou rastros em todo o sistema com o OpenTelemetry. Você aprendeu a instrumentar serviços HTTP e gRPC até agora. Embora você tenha aprendido a instrumentá-los, ainda não aprendeu a analisá-los. Nesta seção, você substituirá os exportadores de stdout pelos exportadores do Cloud Trace e aprenderá a analisar os traces.
Usar o exportador do Cloud Trace
Uma das características poderosas do OpenTelemetry é a conectividade. Para visualizar todos os períodos coletados pela instrumentação, basta substituir o exportador stdout pelo exportador do Cloud Trace.
Abra os arquivos main.go
de cada serviço e encontre a função initTracer()
. Exclua a linha para gerar um exportador stdout e, em vez disso, crie o exportador do 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 }
Você também precisa editar a mesma função no serviço de cliente e de servidor.
Executar o microsserviço e confirmar o trace
Após a edição, execute o cluster como de costume com o comando skaffold.
skaffold dev
Agora você não vê muitas informações do período no formato de registros estruturados em stdout porque o exportador foi substituído pelo Cloud Trace um.
Resposta ao 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 ...
Agora vamos confirmar se todos os períodos foram enviados corretamente para o Cloud Trace. Acesse o console do Cloud e navegue até "Lista de traces". É fácil de acessar a partir da caixa de pesquisa. Caso contrário, clique no menu no painel esquerdo.
Você vai perceber que vários pontos azuis estão distribuídos no gráfico de latência. Cada ponto representa um único trace.
Clique em um deles para conferir os detalhes dentro do rastro.
Mesmo com essa simples visão rápida, você já sabe muitos insights. Por exemplo, no gráfico em cascata, é possível notar que a causa da latência se deve principalmente ao período chamado shakesapp.ShakespeareService/GetMatchCount
. (Consulte "1" na imagem acima) É possível confirmar essa informação na tabela de resumo. A coluna mais à direita mostra a duração de cada período. Além disso, esse trace era para a consulta "friend". (veja 2 na imagem acima)
Com essas análises curtas, você pode perceber que precisa conhecer períodos mais granulares dentro do método GetMatchCount
. Comparada às informações stdout, a visualização é poderosa. Para saber mais sobre o Cloud Trace, acesse nossa documentação oficial.
Resumo
Nesta etapa, você substituiu o exportador stdout pelo Cloud Trace um e visualizou traces no Cloud Trace. Além disso, você aprendeu como começar a analisar os rastros.
A seguir
Na próxima etapa, você modificará o código-fonte do serviço de servidor para adicionar um subdomínio em GetMatchCount.
7. Adicionar um período secundário para melhorar a análise
Na etapa anterior, você descobriu que a causa do tempo de retorno observado no loadgen é principalmente o processo dentro do método GetMatchCount, o gerenciador gRPC, no serviço do servidor. No entanto, como não instrumentamos nada além do gerenciador, não podemos encontrar mais insights do gráfico de cascata. Esse é um caso comum quando começamos a instrumentar microsserviços.
Nesta seção, vamos instrumentar um subdomínio em que o servidor chama o Google Cloud Storage, porque é comum que algumas E/S de rede externa levem muito tempo no processo, e é importante identificar se a chamada é a causa.
Instrumentar um subdomínio no servidor
Abra main.go
no servidor e encontre a função readFiles
. Esta função está chamando uma solicitação ao Google Cloud Storage para buscar todos os arquivos de texto das obras de Shakespeare. Nessa função, você pode criar um subdomínio, como você fez para a instrumentação do servidor HTTP no serviço do cliente.
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 ...
Isso é tudo para adicionar um novo período. Vamos conferir o resultado executando o app.
Executar o microsserviço e confirmar o trace
Após a edição, execute o cluster como de costume com o comando skaffold.
skaffold dev
E escolha um trace chamado query.request
na lista. Você verá um gráfico de cascata de traces semelhante, exceto por um novo período em shakesapp.ShakespeareService/GetMatchCount
. (O espaço delimitado pelo retângulo vermelho abaixo)
O que é possível notar neste gráfico agora é que a chamada externa para o Google Cloud Storage ocupa uma grande quantidade de latência, mas outras coisas ainda estão causando a maior parte da latência.
Você já recebeu muitos insights apenas com alguns Looks do gráfico da cascata de traces. Como você consegue mais detalhes de desempenho em seu aplicativo? Aqui entra o criador de perfil, mas, por enquanto, vamos chegar ao fim deste codelab e delegar todos os tutoriais do Profiler à parte 2.
Resumo
Nessa etapa, você instrumentou outro período no serviço do servidor e recebeu mais insights sobre a latência do sistema.
8. Parabéns
Você criou traces distribuídos com o OpenTelemery e confirmou as latências de solicitação no microsserviço no Google Cloud Trace.
Para exercícios prolongados, você pode experimentar os tópicos a seguir por conta própria.
- A implementação atual envia todos os períodos gerados pela verificação de integridade. (
grpc.health.v1.Health/Check
) Como você filtra esses períodos do Cloud Trace? A dica está aqui. - Relacione logs de eventos com períodos e veja como isso funciona no Google Cloud Trace e no Google Cloud Logging. A dica está aqui.
- Substitua alguns serviços por um em outro idioma e tente instrumentá-los com o OpenTelemetry para esse idioma.
Além disso, se você quiser saber mais sobre o criador de perfil depois disso, avance para a parte 2. Nesse caso, pule a seção de limpeza abaixo.
Limpeza
Após este codelab, interrompa o cluster do Kubernetes e exclua o projeto para não receber cobranças inesperadas no Google Kubernetes Engine, no Google Cloud Trace e no Google Artifact Registry.
Primeiro, exclua o cluster. Se você estiver executando o cluster com skaffold dev
, basta pressionar Ctrl-C. Se você estiver executando o cluster com skaffold run
, execute o seguinte comando:
skaffold delete
Resposta ao comando
Cleaning up... - deployment.apps "clientservice" deleted - service "clientservice" deleted - deployment.apps "loadgen" deleted - deployment.apps "serverservice" deleted - service "serverservice" deleted
Depois de excluir o cluster, no painel de menu, selecione "IAM e Administrador" > "Configurações" e, em seguida, clique em "DESLIGAR" .
Em seguida, insira o ID do projeto (não o nome do projeto) no formulário na caixa de diálogo e confirme o encerramento.