Observabilidad con aplicaciones gRPC sin proxy

Las herramientas de observabilidad de microservicios te permiten instrumentar tus aplicaciones para recoger y presentar datos de telemetría en Cloud Monitoring, Cloud Logging y Cloud Trace de cargas de trabajo de gRPC desplegadas en Google Cloud, incluidas las cargas de trabajo de gRPC en Cloud Service Mesh.

Los clientes y servidores de gRPC se integran con OpenCensus para exportar métricas y trazas a varios backends, incluidos Trace y Monitoring. Puedes hacerlo con los siguientes lenguajes de gRPC:

  • C++
  • Go
  • Java

Lee el resumen de la observabilidad de microservicios y, a continuación, sigue las instrucciones de Configurar la observabilidad de microservicios para instrumentar tus cargas de trabajo de gRPC con el fin de hacer lo siguiente:

Sigue las instrucciones de este documento para llevar a cabo las siguientes tareas:

Ver trazas en Trace

Una vez que hayas completado el proceso de configuración, tus clientes y servidores gRPC instrumentados enviarán trazas a Trace. En la página Información general de Trace de la consola Google Cloud se muestra una lista de los rastreos recientes. Puedes seleccionar un rastreo concreto para ver un desglose de tu tráfico, similar al que se describe en la siguiente sección.

Compatibilidad de los rastreos con el proxy Envoy

La exportación de trazas a Trace con Cloud Service Mesh y el proxy Envoy, tal como se describe en Observabilidad con Envoy, usa la configuración del tracer OpenCensus de Envoy, que permite que las trazas exportadas desde aplicaciones gRPC sin proxy y proxies Envoy sean totalmente compatibles en una malla de servicios. Para que sea compatible con gRPC sin proxy, el bootstrap de Envoy debe configurar el contexto de seguimiento para que incluya el formato de seguimiento GRPC_TRACE_BIN en su OpenCensusConfig. Por ejemplo:

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"]

Exponer la interfaz de administración

A veces, las métricas y los datos de seguimiento no son suficientes para resolver un problema. Es posible que tengas que consultar la configuración o el estado del tiempo de ejecución de la biblioteca gRPC en tu aplicación. Esta información incluye datos sobre el resolvedor, el estado de la conectividad con los peers, estadísticas de RPC en un canal y la configuración recibida de Cloud Service Mesh.

Para obtener esta información, las aplicaciones gRPC pueden exponer la interfaz de administrador en un puerto concreto. Después, puedes consultar la aplicación para saber cómo se configuran los servicios y cómo se ejecutan. En esta sección, encontrarás instrucciones sobre cómo configurar la interfaz de administrador para aplicaciones escritas en cada idioma admitido.

Te recomendamos que crees un servidor gRPC independiente en tu aplicación que escuche en un puerto reservado para este fin. Esto te permite acceder a tus aplicaciones gRPC aunque los puertos de datos no estén accesibles debido a errores de configuración o problemas de red. Te recomendamos que expongas la interfaz de administrador solo en localhost o en un socket de dominio Unix.

En los siguientes fragmentos de código se muestra cómo crear una interfaz de administrador.

C++

En C++, usa este código para crear una interfaz de administrador:

#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

En Go, usa este código para crear una interfaz de administrador:

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

En Java, usa este código para crear una interfaz de administrador:

import io.grpc.services.AdminInterface;

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

Python

En Python, usa este código para crear una interfaz de administrador:

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 conectarse a una VM

El ejemplo de gRPC Wallet ya habilita la interfaz de administrador. Para cambiar el puerto de la interfaz de administración, proporciona la siguiente marca:

 --admin-port=PORT

El puerto de administrador predeterminado es localhost:28881.

Para depurar tu aplicación gRPC, puedes usar SSH para conectarte a una de las VMs que sirven el wallet-service. De esta forma, tendrás acceso a la 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 la herramienta grpcdebug

Para acceder a la interfaz de administrador, necesitas un cliente gRPC que pueda comunicarse con los servicios de administrador de tu aplicación gRPC. En los siguientes ejemplos, se usa una herramienta llamada grpcdebug que puedes descargar e instalar en la VM o el pod en el que se ejecuta tu aplicación gRPC. El repositorio de grpcdebug se encuentra en grpc-ecosystem/grpcdebug.

La versión mínima compatible de Go es la 1.12. La guía oficial de instalación de Go se encuentra en el sitio de Go. Si estás siguiendo la guía para crear una VM Linux para wallet-service, puedes instalar Golang 1.16 con estos 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

Instala la herramienta grpcdebug con los siguientes comandos:

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

Ahora tienes acceso a la interfaz de línea de comandos de grpcdebug. El resultado de la ayuda contiene información sobre los comandos admitidos:

$ 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 obtener más información sobre un comando concreto, utiliza lo siguiente:

 grpcdebug <target address> [command] --help

Usa la herramienta grpcdebug para depurar tus aplicaciones

Puedes usar la herramienta grpcdebug para depurar tus aplicaciones. La herramienta grpcdebug proporciona una configuración similar a ssh_config que admite alias, reescritura de nombres de host y configuración de seguridad de conexión (insegura o TLS). Para obtener más información sobre esta función avanzada, consulta grpcdebug/Connect&Security.

En las siguientes secciones se describen los servicios expuestos por la interfaz de administrador y cómo acceder a ellos.

Usar Channelz

El servicio Channelz proporciona acceso a información sobre el tiempo de ejecución de las conexiones en diferentes niveles de la biblioteca gRPC de tu aplicación. Puedes usarlo para analizar en directo las aplicaciones que puedan tener problemas relacionados con la configuración o la red. En los ejemplos siguientes se da por hecho que has implementado el ejemplo de gRPC Wallet siguiendo las instrucciones de Configurar la gestión avanzada del tráfico con servicios de gRPC sin proxy y que has proporcionado la siguiente marca:

 --admin-port=PORT

Después de enviar algunas llamadas a procedimiento remoto desde un cliente de prueba, como se muestra en Verificar la configuración, usa los siguientes comandos para acceder a los datos de Channelz de los servicios gRPC:

  1. Usa SSH para conectarte a una máquina virtual que ejecute wallet-service.
  2. Configura grpcdebug para conectarte a la aplicación gRPC en ejecución.

El resultado predeterminado de grpcdebug se muestra en una tabla con un formato compatible con la consola. Si proporcionas la marca --json, la salida se codifica como JSON.

El comando grpcdebug channelz se usa para obtener y presentar información de depuración del servicio Channelz. El comando funciona tanto para clientes gRPC como para servidores gRPC.

En el caso de los clientes de gRPC, el comando grpcdebug channelz channels proporciona una lista de los canales existentes y cierta información básica:

$ 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

Si necesitas más información sobre un canal concreto, puedes usar grpcdebug channelz channel [CHANNEL_ID] para consultar información detallada sobre él. El identificador de canal puede ser el ID del canal o la dirección de destino, si solo hay una dirección de destino. Un canal de gRPC puede contener varios subcanales, que es la abstracción de gRPC sobre una conexión 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

También puedes consultar información detallada de un 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

Puedes obtener información sobre los sockets 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

En el lado del servidor, puedes usar Channelz para inspeccionar el estado de tu aplicación de servidor. Por ejemplo, puedes obtener la lista de servidores con el 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 obtener más información sobre un servidor concreto, usa el comando grpcdebug channelz server. Puedes inspeccionar los sockets de servidor de la misma forma que los sockets 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 el servicio de descubrimiento del estado del cliente

La API Client Status Discovery Service (CSDS) forma parte de las APIs xDS. En una aplicación gRPC, el servicio CSDS proporciona acceso a la configuración (también llamada configuración xDS) que recibe de Cloud Service Mesh. De esta forma, puedes identificar y resolver problemas relacionados con la configuración de tu malla.

En los ejemplos siguientes se da por hecho que ha implementado el ejemplo de gRPC Wallet siguiendo las instrucciones de Configurar la gestión avanzada del tráfico con servicios de gRPC sin proxy.

Para usar CSDS y examinar la configuración, sigue estos pasos:

  1. Usa SSH para conectarte a una máquina virtual que ejecute wallet-service. Sigue las instrucciones de la sección Usar SSH para conectarse a una VM.
  2. Ejecuta el cliente grpcdebug.

Para obtener una descripción general del estado de la configuración, ejecuta el siguiente comando:

grpcdebug localhost:28881 xds status

Verá resultados similares a los siguientes:

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

Puedes encontrar la definición del estado de configuración en la documentación del proxy de Envoy. En resumen, el estado de un recurso xDS es REQUESTED, DOES_NOT_EXIST, ACKED o NACKED.

Para obtener un volcado de configuración xDS sin formato, ejecuta el siguiente comando:

grpcdebug localhost:28881 xds config

Verás una JSON lista del PerXdsConfig objeto:

{
  "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":  [
              {
...

Si la salida de configuración sin procesar es demasiado detallada, grpcdebug te permite filtrar en función de tipos de xDS específicos. Por ejemplo:

$ 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",
...

También puedes volcar la configuración de varios tipos de xDS al mismo tiempo:

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

Siguientes pasos