O Managed Service for OpenTelemetry oferece aos desenvolvedores de aplicações distribuídas um conjunto completo de ferramentas, incluindo visualização de traces, estatísticas de volume de requisições, topologia de aplicações e análise de dependências. Este tópico descreve como usar headers para implementar o rastreamento gRPC no ASM.
Pré-requisitos
Você criou uma instância do ASM. Para mais informações, consulte Create an ASM instance.
Você ativou o Managed Service for OpenTelemetry. Para informações sobre faturamento, consulte Billing.
Projeto de exemplo
O projeto gRPC de exemplo está disponível em hello-servicemesh-grpc. Todos os diretórios mencionados neste tópico estão no repositório hello-servicemesh-grpc.
Práticas de programação com headers gRPC
Recuperar headers no servidor
-
Métodos básicos
-
Java: Recuperar headers no servidor.
Implemente o método
ServerInterceptorda interfaceinterceptCall(ServerCall<ReqT, RespT> call,final Metadata m,ServerCallHandler<ReqT, RespT> h). UseString v = m.get(k)para obter as informações do header. O tipo do parâmetro do métodogetéMetadata.Key<String>. -
Go: Recuperar headers no servidor.
metadata.FromIncomingContext(ctx)(md MD, ok bool), onde MD é ummap[string][]string. -
Node.js: Recuperar headers no servidor.
O tipo de retorno de
call.metadata.getMap()é[key: string]: MetadataValue, e o tipoMetadataValueé definido comostring/Buffer. -
Python: Recuperar headers no servidor.
context.invocation_metadata()retorna um array de tuplas de 2 elementos no formato('k','v'). Usem.key, m.valuepara obter o par chave-valor.
-
-
Unary RPC
-
Java: Recuperar headers para unary RPC.
O método não tem acesso aos headers.
-
Go: Recuperar headers para unary RPC.
No método, chame diretamente
metadata.FromIncomingContext(ctx). O parâmetro de contextoctxvem do parâmetro de entrada do métodoTalk. -
Node.js: Recuperar headers para unary RPC.
Chame diretamente
call.metadata.getMap()dentro do método. -
Python: Recuperar headers para unary RPC.
Chame diretamente
context.invocation_metadata()dentro do método.
-
-
Server streaming RPC
-
Java: Recuperar headers para server streaming RPC.
O método não tem acesso aos headers.
-
Go: Recuperar headers para server streaming RPC.
No método, chame diretamente
metadata.FromIncomingContext(ctx). O parâmetro de contextoctxé obtido do parâmetro de entradastreamdeTalkOneAnswerMore, chamandostream.Context(). -
Node.js: Recuperar headers para server streaming RPC.
Chame
call.metadata.getMap()diretamente dentro do método. -
Python: Recuperar headers para server streaming RPC.
Chame diretamente
context.invocation_metadata()dentro do método.
-
-
Client streaming RPC
-
Java: Recuperar headers para client streaming RPC.
O método não tem acesso aos headers.
-
Go: Recuperar headers para client streaming RPC.
No método, chame diretamente
metadata.FromIncomingContext(ctx). O parâmetro de contextoctxé obtido chamandostream.Context()sobre o parâmetro de entradastreamdo métodoTalkMoreAnswerOne. -
Node.js: Recuperar headers para client streaming RPC.
Chame diretamente
call.metadata.getMap()dentro do método. -
Python: Recuperar headers para client streaming RPC.
Chame diretamente
context.invocation_metadata()dentro do método.
-
-
Bidirectional streaming RPC
-
Java: Recuperar headers para bidirectional streaming RPC.
O método não tem acesso aos headers.
-
Go: Recuperar headers para bidirectional streaming RPC.
No método, chame diretamente
metadata.FromIncomingContext(ctx). O parâmetro de contextoctxé obtido destream.Context(), chamado sobre o parâmetro de entradastreamdo métodoTalkBidirectional. -
Node.js: Recuperar headers para bidirectional streaming RPC.
Chame diretamente
call.metadata.getMap()dentro do método. -
Python: Recuperar headers para bidirectional streaming RPC.
Chame diretamente
context.invocation_metadata()no método.
-
Enviar headers a partir do cliente
-
Métodos básicos
-
Java: Enviar headers a partir do cliente.
Implemente o método
ClientInterceptorda interfaceinterceptCall(MethodDescriptor<ReqT, RespT> m,CallOptions o, Channel c), e no objetoClientCall<ReqT,RespT>retornado, implemente o métodostart((Listener<RespT> l, Metadata h)). Useh.put(k, v)para adicionar informações ao header. No métodoput, o parâmetroké do tipoMetadata.Key<String>, evé do tipoString. -
Go: Enviar headers a partir do cliente.
metadata.AppendToOutgoingContext(ctx,kv ...) context.Context -
Node.js: Enviar headers a partir do cliente.
metadata=call.metadata.getMap()metadata.add(key, headers[key]) -
Python: Enviar headers a partir do cliente.
A variável
metadata_dict = {}é preenchida commetadata_dict[c.key] = c.valuee, por fim, convertida para o tipolist tuplepor meio delist(metadata_dict.items()).
-
-
Unary RPC
-
Java: Enviar headers para unary RPC.
O método não tem acesso aos headers.
-
Go: Enviar headers para unary RPC.
No método, chame diretamente
metadata.AppendToOutgoingContext(ctx,kv). -
Node.js: Enviar headers para unary RPC.
Use o método básico diretamente dentro do seu método RPC.
-
Python: Enviar headers para unary RPC.
Use o método básico diretamente dentro do seu método RPC.
-
-
Server streaming RPC
-
Java: Enviar headers para server streaming RPC.
O método não tem acesso aos headers.
-
Go: Enviar headers para server streaming RPC.
Chame diretamente
metadata.AppendToOutgoingContext(ctx,kv)no método. -
Node.js: Enviar headers para server streaming RPC.
Use o método básico diretamente dentro do seu método RPC.
-
Python: Enviar headers para server streaming RPC.
Use o método básico diretamente dentro do seu método RPC.
-
-
Client streaming RPC
-
Java: Enviar headers para client streaming RPC.
O método não tem acesso aos headers.
-
Go: Enviar headers para client streaming RPC.
Chame diretamente
metadata.AppendToOutgoingContext(ctx,kv)no método. -
Node.js: Enviar headers para client streaming RPC.
Use o método básico diretamente dentro do seu método RPC.
-
Python: Enviar headers para client streaming RPC.
Use o método básico diretamente dentro do seu método RPC.
-
-
Bidirectional streaming RPC
-
Java: Enviar headers para bidirectional streaming RPC.
O método não tem acesso aos headers.
-
Go: Enviar headers para bidirectional streaming RPC.
Chame diretamente
metadata.AppendToOutgoingContext(ctx,kv)no método. -
Node.js: Enviar headers para bidirectional streaming RPC.
Use o método básico diretamente dentro do seu método RPC.
-
Python: Enviar headers para bidirectional streaming RPC.
Use o método básico diretamente dentro do seu método RPC.
-
Propagação de headers
Para que o rastreamento de ponta a ponta funcione, os metadados de trace de um service upstream precisam ser repassados aos services downstream, formando um trace completo. Isso exige que os headers relacionados ao rastreamento recebidos pelo servidor sejam propagados ao cliente que faz a requisição downstream.
Em Go, Node.js e Python, os métodos do modelo de comunicação têm acesso aos headers, o que permite ler, repassar e enviar headers de forma sequencial dentro do mesmo método RPC.
Em Java, a leitura e a escrita de headers são tratadas por dois interceptors separados. Isso impede a implementação da propagação de headers em um único processo sequencial. Devido à concorrência e ao acesso exclusivo do interceptor de leitura ao trace ID único, não é possível usar um mecanismo de cache simples para conectar os dois interceptors.
O Java oferece um mecanismo de Metadata-Context Propagation para resolver esse problema.
No interceptor do servidor, armazene o Metadata/Header no Context usando ctx.withValue(key, metadata), onde key é do tipo Context.Key<String>. Em seguida, no interceptor do cliente, recupere o Metadata from the Context usando key.get(). O método get utiliza por padrão o contexto Context.current(), garantindo que os headers de uma única requisição sejam lidos e gravados no mesmo contexto.
Com esse mecanismo de propagação em vigor, é possível implementar de forma confiável o rastreamento para serviços baseados em gRPC.
Implantar e verificar a topologia do mesh
Antes de implementar o rastreamento gRPC, implante e verifique a topologia do mesh para garantir que todos os serviços consigam se comunicar entre si.
Acesse o diretório de rastreamento no projeto de exemplo. Esse diretório contém scripts de implantação para as quatro linguagens de programação. O exemplo a seguir usa a versão Go para implantar e verificar a topologia do mesh.
cd go
# Deploy the topology
sh apply.sh
# Verify the topology
sh test.sh
Se nenhum erro for reportado, a topologia do mesh está se comunicando corretamente.
A topologia do Service Mesh após a implantação é exibida na figura a seguir.
Visualizar traces
Configure sua instância do ASM para reportar dados de trace ao Managed Service for OpenTelemetry. Para mais informações, consulte Configure ASM to report trace data.
Faça login no console do Managed Service for OpenTelemetry. No painel de navegação à esquerda, clique em Trace Entrance.
-
Na página Trace Entrance, localize a aplicação desejada e clique em Application Topology.
É possível visualizar o trace completo, que inclui o caminho do cliente de requisição local até o Ingressgateway, passando por grpc-server-svc1, grpc-server-svc2 e grpc-server-svc3. A página exibe uma topologia vertical da cadeia de chamadas de service da aplicação alvo (como
istio-ingressgateway), mostrando os relacionamentos de chamada deistio-ingressgatewaypara múltiplas camadas de serviçosgrpc-server. Cada nó é rotulado com sua taxa de sucesso e multiplicador de chamadas. -
Na página End-to-End Aggregation, clique na aba End-to-End Aggregation para visualizar a agregação de ponta a ponta.
A página End-to-End Aggregation exibe informações de trace agregadas em uma tabela hierárquica. As colunas incluem Span name, Application name, Requests/request ratio, Spans/request, Avg. self duration/ratio, Avg. duration e Errors/error ratio. Expanda cada nível da hierarquia de chamadas para visualizar as métricas de desempenho de cada Span.
-
Na aba End-to-End Aggregation, clique em um trace na coluna Span name para visualizar seus detalhes.
A parte superior da página de detalhes do trace exibe metadados, incluindo Start time, Duration, Applications, Trace depth e Total spans. A tabela abaixo apresenta uma visão hierárquica de cada Span, com colunas para Span name, visualização de Timeline, Application name, Start time, IP address e Status. Isso permite visualizar a hierarquia de chamadas e a distribuição de duração entre os serviços.