Observabilidade com aplicativos gRPC sem proxy

As ferramentas de observabilidade de microsserviços oferecem a capacidade de instrumentar seus aplicativos para coletar e apresentar dados de telemetria no Cloud Monitoring, Cloud Logging e Cloud Trace usando cargas de trabalho do gRPC implantadas no Google Cloud, incluindo cargas de trabalho de gRPC no Cloud Service Mesh.

Os clientes e servidores gRPC são integrados ao OpenCensus para exportar métricas e traces para vários back-ends, incluindo o Trace e o Monitoring. Para fazer isso, use as seguintes linguagens do gRPC:

  • C++
  • Go
  • Java

Leia a Visão geral da observabilidade de microsserviços e use as instruções em Configurar a observabilidade de microsserviços para instrumentar suas cargas de trabalho do gRPC para:

Use as instruções neste documento para as seguintes tarefas:

Visualizar traces no Trace

Depois de concluir o processo de configuração, os clientes e servidores gRPC instrumentados enviam traces para o Trace. A página Visão geral do trace no Console do Google Cloud mostra uma lista de traces recentes. É possível selecionar um trace individual para ver um detalhamento do seu tráfego, de maneira semelhante ao que é descrito na seção a seguir.

Compatibilidade do Trace com o proxy Envoy

A exportação de traces para o Trace com o Cloud Service Mesh e o proxy Envoy, conforme descrito em Observabilidade com o Envoy, usa a configuração do rastreador do OpenCensus do Envoy, que permite que os traces exportados de aplicativos gRPC sem proxy e os proxies do Envoy sejam totalmente compatíveis em uma malha de serviço. Para compatibilidade com o gRPC sem proxy, o bootstrap do Envoy precisa configurar o contexto de rastreamento para incluir o formato de trace GRPC_TRACE_BIN no OpenCensusConfig. Exemplo:

tracing:
  http:
      name: envoy.tracers.opencensus
      typed_config:
        "@type": type.googleapis.com/envoy.config.trace.v2.OpenCensusConfig
        stackdriver_exporter_enabled: "true"
        stackdriver_project_id: "PROJECT_ID"
        incoming_trace_context: ["CLOUD_TRACE_CONTEXT", "GRPC_TRACE_BIN"]
        outgoing_trace_context: ["CLOUD_TRACE_CONTEXT", "GRPC_TRACE_BIN"]

Expor a interface de administração

Sometimess vezes, os dados de métricas e rastreamento não são suficientes para resolver um problema. Talvez seja necessário analisar a configuração ou o estado do ambiente de execução da biblioteca gRPC no seu aplicativo. Essas informações incluem informações do resolvedor, o estado da conectividade com peering, estatísticas de RPC em um canal e a configuração recebida do Cloud Service Mesh.

Para conseguir essas informações, os aplicativos do gRPC podem expor a interface administrativa em uma porta específica. Em seguida, consulte o aplicativo para entender como os serviços são configurados e como estão sendo executados. Nesta seção, você encontra instruções sobre como configurar a interface administrativa para aplicativos escritos em cada linguagem compatível.

Recomendamos que você crie um servidor gRPC separado no aplicativo que detecte em uma porta reservada para essa finalidade. Isso permite que você acesse seus aplicativos gRPC mesmo quando as portas de dados estão inacessíveis por causa de problemas de configuração ou de rede. Recomendamos que a interface administrativa seja exposta apenas em localhost ou em um soquete de domínio Unix.

Os snippets de código a seguir mostram como criar uma interface de administração.

C++

Em C++, use este código para criar uma interface administrativa:

#include <grpcpp/ext/admin_services.h>

grpc::ServerBuilder builder;
grpc::AddAdminServices(&builder);
builder.AddListeningPort(":50051", grpc::ServerCredentials(...));
std::unique_ptr<grpc::Server> server(builder.BuildAndStart());

Go

No Go, use este código para criar uma interface administrativa:

import "google.golang.org/grpc/admin"

lis, err := net.Listen("tcp", ":50051")
if err != nil {
        log.Fatalf("failed to listen: %v", err)
}
defer lis.Close()
grpcServer := grpc.NewServer(...opts)
cleanup, err := admin.Register(grpcServer)
if err != nil {
        log.Fatalf("failed to register admin services: %v", err)
}
defer cleanup()

if err := grpcServer.Serve(lis); err != nil {
        log.Fatalf("failed to serve: %v", err)
}

Java

Em Java, use este código para criar uma interface administrativa:

import io.grpc.services.AdminInterface;

server = ServerBuilder.forPort(50051)
        .useTransportSecurity(certChainFile, privateKeyFile)
        .addServices(AdminInterface.getStandardServices())
        .build()
        .start();
server.awaitTermination();

Python

No Python, use este código para criar uma interface administrativa:

import grpc_admin

server = grpc.server(futures.ThreadPoolExecutor())
grpc_admin.add_admin_servicers(server)
server.add_insecure_port('[::]:50051')
server.start()
server.wait_for_termination()

Usar SSH para se conectar a uma VM

O exemplo gRPC Wallet já ativa a interface do administrador. É possível alterar a porta da interface administrativa fornecendo a seguinte sinalização:

 --admin-port=PORT

A porta administrativa padrão é localhost:28881.

Para depurar seu aplicativo gRPC, use o SSH para se conectar a uma das VMs que disponibilizam o wallet-service. Isso dá acesso ao localhost.

# List the Wallet VMs
$ gcloud compute instances list --filter="zone:(us-central1-a)" --filter="name~'grpcwallet-wallet-v2'"
NAME                                       ZONE            MACHINE_TYPE   PREEMPTIBLE  INTERNAL_IP    EXTERNAL_IP     STATUS
grpcwallet-wallet-v2-mig-us-central1-ccl1  us-central1-a   n1-standard-1               10.240.0.38    35.223.42.98    RUNNING
grpcwallet-wallet-v2-mig-us-central1-k623  us-central1-a   n1-standard-1               10.240.0.112   35.188.133.75   RUNNING
# Pick one of the Wallet VMs to debug
$ gcloud compute ssh grpcwallet-wallet-v2-mig-us-central1-ccl1 --zone=us-central1-a

Instalar a grpcdebug ferramenta

Para acessar a interface administrativa, você precisa de um cliente gRPC que possa se comunicar com os serviços administrativos no aplicativo gRPC. Nos exemplos a seguir, use uma ferramenta chamada grpcdebug. É possível fazer o download e instalá-la na VM ou no pod em que o aplicativo gRPC está em execução. O repositório de grpcdebug está localizado em grpc-ecosystem/grpcdebug.

A versão mínima de Golang compatível é 1.12. O guia de instalação oficial do Golang está no site do Golang. Se você estiver seguindo o guia para criar uma VM do Linux para wallet-service, poderá instalar o Golang 1.16 usando estes comandos:

sudo apt update && sudo apt install -y wget
wget https://golang.org/dl/go1.16.3.linux-amd64.tar.gz
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf go1.16.3.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin
sudo ln -sf /usr/local/go/bin/go /usr/bin/go
go version
# go version go1.16.3 linux/amd64

Instale a ferramenta grpcdebug com os seguintes comandos:

go install -v github.com/grpc-ecosystem/grpcdebug@latest
export PATH=$PATH:$(go env GOPATH)/bin

Agora você tem acesso à interface de linha de comando grpcdebug. A saída de ajuda contém informações sobre os comandos compatíveis:

$ grpcdebug -h
grpcdebug is a gRPC service admin command-line interface

Usage:
  grpcdebug <target address> [flags]  <command>

Available Commands:
  channelz    Display gRPC states in human readable way.
  health      Check health status of the target service (default "").
  help        Help about any command
  xds         Fetch xDS related information.

Flags:
      --credential_file string        Sets the path of the credential file; used in [tls] mode
  -h, --help                          Help for grpcdebug
      --security string               Defines the type of credentials to use [tls, google-default, insecure] (default "insecure")
      --server_name_override string   Overrides the peer server name if non empty; used in [tls] mode
  -t, --timestamp                     Print timestamp as RFC 3339 instead of human readable strings
  -v, --verbose                       Print verbose information for debugging

Para ver mais informações sobre um determinado comando, use o seguinte:

 grpcdebug <target address> [command] --help

Como usar a ferramenta grpcdebug para depurar seus aplicativos

Use a ferramenta grpcdebug para depurar seus aplicativos. A ferramenta grpcdebug fornece uma configuração semelhante a ssh_config, que é compatível com alias, regravação de nome do host e configuração de segurança da conexão (insegura/TLS). Para mais informações sobre esse recurso avançado, consulte grpcdebug/Connect&Security.

As seções a seguir descrevem os serviços expostos pela interface administrativo e como acessá-los.

Usar Channelz

O serviço Channelz fornece acesso a informações no ambiente de execução sobre as conexões em diferentes níveis na biblioteca gRPC do aplicativo. Use isso para análise em tempo real de aplicativos que possam ter problemas relacionados à configuração ou à rede. Os exemplos a seguir presumem que você implantou o exemplo do gRPC Wallet usando as instruções em Configurar o gerenciamento de tráfego avançado com serviços gRPC sem proxy e que forneceu a seguinte sinalização:

 --admin-port=PORT

Depois de enviar algumas RPCs de um cliente de teste, conforme mostrado em Como verificar a configuração, use os seguintes comandos para acessar os dados do Channelz para serviços gRPC.

  1. Use SSH para se conectar a uma VM que esteja executando o wallet-service.
  2. Configure grpcdebug para se conectar ao aplicativo gRPC em execução.

A saída padrão de grpcdebug está em um formato de tabela compatível com o console. Se você fornecer a sinalização --json, a saída será codificada como JSON.

O comando grpcdebug channelz é usado para buscar e apresentar informações de depuração do serviço Channelz. O comando funciona para clientes e servidores gRPC.

Para clientes gRPC, o comando grpcdebug channelz channels fornece uma lista de canais existentes e algumas informações básicas:

$ grpcdebug localhost:28881 channelz channels
Channel ID   Target                               State     Calls(Started/Succeeded/Failed)   Created Time
1            xds:///account.grpcwallet.io:10080   READY     0/0/0                             59 seconds ago
2            trafficdirector.googleapis.com:443   READY     2/0/0                             59 seconds ago
4            xds:///stats.grpcwallet.io:10080     READY     0/0/0                             59 seconds ago

Se você precisar de mais informações sobre um canal específico, use grpcdebug channelz channel [CHANNEL_ID] para inspecionar as informações detalhadas do canal. O identificador do canal pode ser o ID do canal ou o endereço de destino, se houver apenas um endereço de destino. Um canal gRPC pode conter vários subcanais, que é a abstração do gRPC sobre uma conexão TCP.

$ grpcdebug localhost:28881 channelz channel 2
Channel ID:        2
Target:            trafficdirector.googleapis.com:443
State:             READY
Calls Started:     2
Calls Succeeded:   0
Calls Failed:      0
Created Time:      10 minutes ago
---
Subchannel ID   Target                               State     Calls(Started/Succeeded/Failed)   CreatedTime
3               trafficdirector.googleapis.com:443   READY     2/0/0                             10 minutes ago
---
Severity   Time             Child Ref                      Description
CT_INFO    10 minutes ago                                  Channel Created
CT_INFO    10 minutes ago                                  parsed scheme: ""
CT_INFO    10 minutes ago                                  scheme "" not registered, fallback to default scheme
CT_INFO    10 minutes ago                                  ccResolverWrapper: sending update to cc: {[{trafficdirector.googleapis.com:443  <nil> 0 <nil>}] <nil> <nil>}
CT_INFO    10 minutes ago                                  Resolver state updated: {Addresses:[{Addr:trafficdirector.googleapis.com:443 ServerName: Attributes:<nil> Type:0 Metadata:<nil>}] ServiceConfig:<nil> Attributes:<nil>} (resolver returned new addresses)
CT_INFO    10 minutes ago                                  ClientConn switching balancer to "pick_first"
CT_INFO    10 minutes ago                                  Channel switches to new LB policy "pick_first"
CT_INFO    10 minutes ago   subchannel(subchannel_id:3 )   Subchannel(id:3) created
CT_INFO    10 minutes ago                                  Channel Connectivity change to CONNECTING
CT_INFO    10 minutes ago                                  Channel Connectivity change to READY

Você também pode inspecionar informações detalhadas sobre um subcanal:

$ grpcdebug localhost:28881 channelz subchannel 3
Subchannel ID:     3
Target:            trafficdirector.googleapis.com:443
State:             READY
Calls Started:     2
Calls Succeeded:   0
Calls Failed:      0
Created Time:      12 minutes ago
---
Socket ID   Local->Remote                           Streams(Started/Succeeded/Failed)   Messages(Sent/Received)
9           10.240.0.38:60338->142.250.125.95:443   2/0/0                               214/132

É possível recuperar informações sobre soquetes TCP:

$ grpcdebug localhost:28881 channelz socket 9
Socket ID:                       9
Address:                         10.240.0.38:60338->142.250.125.95:443
Streams Started:                 2
Streams Succeeded:               0
Streams Failed:                  0
Messages Sent:                   226
Messages Received:               141
Keep Alives Sent:                0
Last Local Stream Created:       12 minutes ago
Last Remote Stream Created:      a long while ago
Last Message Sent Created:       8 seconds ago
Last Message Received Created:   8 seconds ago
Local Flow Control Window:       65535
Remote Flow Control Window:      966515
---
Socket Options Name   Value
SO_LINGER             [type.googleapis.com/grpc.channelz.v1.SocketOptionLinger]:{duration:{}}
SO_RCVTIMEO           [type.googleapis.com/grpc.channelz.v1.SocketOptionTimeout]:{duration:{}}
SO_SNDTIMEO           [type.googleapis.com/grpc.channelz.v1.SocketOptionTimeout]:{duration:{}}
TCP_INFO              [type.googleapis.com/grpc.channelz.v1.SocketOptionTcpInfo]:{tcpi_state:1  tcpi_options:7  tcpi_rto:204000  tcpi_ato:40000  tcpi_snd_mss:1408  tcpi_rcv_mss:1408  tcpi_last_data_sent:8212  tcpi_last_data_recv:8212  tcpi_last_ack_recv:8212  tcpi_pmtu:1460  tcpi_rcv_ssthresh:88288  tcpi_rtt:2400  tcpi_rttvar:3012  tcpi_snd_ssthresh:2147483647  tcpi_snd_cwnd:10  tcpi_advmss:1408  tcpi_reordering:3}
---
Security Model:   TLS
Standard Name:    TLS_AES_128_GCM_SHA256

No lado do servidor, é possível usar o Channelz para inspecionar o status do aplicativo do servidor. Por exemplo, é possível conseguir a lista de servidores usando o comando grpcdebug channelz servers:

$ grpcdebug localhost:28881 channelz servers
Server ID   Listen Addresses    Calls(Started/Succeeded/Failed)   Last Call Started
5           [127.0.0.1:28881]   9/8/0                             now
6           [[::]:50051]        159/159/0                         4 seconds ago

Para mais informações sobre um servidor específico, use o comando grpcdebug channelz server. É possível inspecionar soquetes de servidor da mesma maneira que inspeciona soquetes de cliente.

$ grpcdebug localhost:28881 channelz server 6
Server Id:           6
Listen Addresses:    [[::]:50051]
Calls Started:       174
Calls Succeeded:     174
Calls Failed:        0
Last Call Started:   now
---
Socket ID   Local->Remote                            Streams(Started/Succeeded/Failed)   Messages(Sent/Received)
25          10.240.0.38:50051->130.211.1.39:44904    68/68/0                             68/68
26          10.240.0.38:50051->130.211.0.167:32768   54/54/0                             54/54
27          10.240.0.38:50051->130.211.0.22:32768    52/52/0                             52/52

Usar o serviço de descoberta de status do cliente

A API Client Status Discovery Service (CSDS) faz parte das APIs xDS. Em um aplicativo gRPC, o serviço CSDS fornece acesso à configuração (também chamada de configuração xDS) que recebe do Cloud Service Mesh. Isso permite que você identifique e resolva problemas relacionados à configuração na malha.

Os exemplos a seguir presumem que você implantou o exemplo da carteira de gRPC usando as instruções em Configurar o gerenciamento de tráfego avançado com serviços gRPC sem proxy.

Para usar o CSDS para examinar a configuração:

  1. Use SSH para se conectar a uma VM que esteja executando o wallet-service. Siga as instruções em Usar SSH para se conectar a uma VM.
  2. Execute o cliente grpcdebug.

Para ter uma visão geral do status de configuração, execute o seguinte comando:

grpcdebug localhost:28881 xds status

Você verá resultados parecidos com o seguinte:

Name                                                                    Status    Version               Type                                                                 LastUpdated
account.grpcwallet.io:10080                                             ACKED     1618529574783547920   type.googleapis.com/envoy.config.listener.v3.Listener                3 seconds ago
stats.grpcwallet.io:10080                                               ACKED     1618529574783547920   type.googleapis.com/envoy.config.listener.v3.Listener                3 seconds ago
URL_MAP/830293263384_grpcwallet-url-map_0_account.grpcwallet.io:10080   ACKED     1618529574783547920   type.googleapis.com/envoy.config.route.v3.RouteConfiguration         3 seconds ago
URL_MAP/830293263384_grpcwallet-url-map_1_stats.grpcwallet.io:10080     ACKED     1618529574783547920   type.googleapis.com/envoy.config.route.v3.RouteConfiguration         3 seconds ago
cloud-internal-istio:cloud_mp_830293263384_3566964729007423588          ACKED     1618529574783547920   type.googleapis.com/envoy.config.cluster.v3.Cluster                  3 seconds ago
cloud-internal-istio:cloud_mp_830293263384_7383783194368524341          ACKED     1618529574783547920   type.googleapis.com/envoy.config.cluster.v3.Cluster                  3 seconds ago
cloud-internal-istio:cloud_mp_830293263384_3363366193797120473          ACKED     1618529574783547920   type.googleapis.com/envoy.config.cluster.v3.Cluster                  3 seconds ago
cloud-internal-istio:cloud_mp_830293263384_3566964729007423588          ACKED     86                    type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment   2 seconds ago
cloud-internal-istio:cloud_mp_830293263384_3363366193797120473          ACKED     86                    type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment   2 seconds ago
cloud-internal-istio:cloud_mp_830293263384_7383783194368524341          ACKED     86                    type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment   2 seconds ago

A definição do status de configuração fica na documentação do proxy Envoy. Em resumo, o status de um recurso xDS é REQUESTED, DOES_NOT_EXIST, ACKED ou NACKED.

Para receber um dump de configuração xDS bruta, execute o seguinte comando:

grpcdebug localhost:28881 xds config

Aparecerá uma lista de JSON do objeto PerXdsConfig:

{
  "config":  [
    {
      "node":  {
        "id":  "projects/830293263384/networks/default/nodes/6e98b038-6d75-4a4c-8d35-b0c7a8c9cdde",
        "cluster":  "cluster",
        "metadata":  {
          "INSTANCE_IP":  "10.240.0.38",
          "TRAFFICDIRECTOR_GCP_PROJECT_NUMBER":  "830293263384",
          "TRAFFICDIRECTOR_NETWORK_NAME":  "default"
        },
        "locality":  {
          "zone":  "us-central1-a"
        },
        "userAgentName":  "gRPC Go",
        "userAgentVersion":  "1.37.0",
        "clientFeatures":  [
          "envoy.lb.does_not_support_overprovisioning"
        ]
      },
      "xdsConfig":  [
        {
          "listenerConfig":  {
            "versionInfo":  "1618529930989701137",
            "dynamicListeners":  [
              {
...

Se a saída da configuração bruta for muito detalhada, o grpcdebug permitirá filtrar com base em tipos de xDS específicos. Exemplo:

$ grpcdebug localhost:28881 xds config --type=cds
{
  "versionInfo":  "1618530076226619310",
  "dynamicActiveClusters":  [
    {
      "versionInfo":  "1618530076226619310",
      "cluster":  {
        "@type":  "type.googleapis.com/envoy.config.cluster.v3.Cluster",
        "name":  "cloud-internal-istio:cloud_mp_830293263384_7383783194368524341",
        "altStatName":  "/projects/830293263384/global/backendServices/grpcwallet-stats-service",
        "type":  "EDS",
        "edsClusterConfig":  {
          "edsConfig":  {
            "ads":  {},
            "initialFetchTimeout":  "15s",
...

Também é possível fazer o dump da configuração de vários tipos xDSs ao mesmo tempo:

$ grpcdebug localhost:28881 xds config --type=lds,eds
{
  "versionInfo":  "1618530076226619310",
  "dynamicListeners":  [...]
}
{
  "dynamicEndpointConfigs":  [...]
}

A seguir