Osservabilità con applicazioni gRPC senza proxy

Gli strumenti di osservabilità dei microservizi ti consentono di instrumentare le tue applicazioni per raccogliere e presentare i dati di telemetria in Cloud Monitoring, Cloud Logging e Cloud Trace dai carichi di lavoro gRPC di cui è stato eseguito il deployment su Google Cloud, inclusi i carichi di lavoro gRPC in Cloud Service Mesh.

I client e i server gRPC sono integrati con OpenCensus per esportare metriche e tracce in vari backend, tra cui Trace e Monitoring. Puoi farlo con i seguenti linguaggi gRPC:

  • C++
  • Vai
  • Java

Leggi la Panoramica dell'osservabilità dei microservizi, quindi segui le istruzioni riportate in Configurare l'osservabilità dei microservizi per eseguire l'instrumentazione dei carichi di lavoro gRPC per quanto segue:

Segui le istruzioni riportate in questo documento per le seguenti attività:

Visualizzare le tracce in Trace

Dopo aver completato la procedura di configurazione, i client e i server gRPC instrumentati inviano le tracce a Trace. La pagina Panoramica dei trace nella Google Cloud console mostra un elenco dei trace recenti. Puoi selezionare una singola traccia per visualizzare una suddivisione del traffico, simile a quanto descritto nella sezione seguente.

Compatibilità della traccia con il proxy Envoy

L'esportazione delle tracce in Trace con Cloud Service Mesh e il proxy Envoy, come descritto in Osservabilità con Envoy, utilizza la configurazione del tracer OpenCensus di Envoy, che consente alle tracce esportate da applicazioni gRPC proxyless e proxy Envoy di essere completamente compatibili all'interno di un mesh di servizi. Per la compatibilità con gRPC proxyless, il bootstrap di Envoy deve configurare il contesto della traccia in modo da includere il formato della traccia GRPC_TRACE_BIN nel proprio OpenCensusConfig. Ad esempio:

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

Esporre l'interfaccia di amministrazione

A volte, le metriche e i dati di monitoraggio non sono sufficienti per risolvere un problema. Potresti dover esaminare la configurazione o lo stato di runtime della libreria gRPC nella tua applicazione. Queste informazioni includono informazioni sul resolver, lo stato della connettività ai peer, le statistiche RPC su un canale e la configurazione ricevuta da Cloud Service Mesh.

Per ottenere queste informazioni, le applicazioni gRPC possono esporre l'interfaccia di amministrazione su una determinata porta. Puoi quindi eseguire query sull'applicazione per capire come sono configurati e in esecuzione i servizi. In questa sezione puoi trovare le istruzioni su come configurare l'interfaccia di amministrazione per le applicazioni scritte in ogni lingua supportata.

Ti consigliamo di creare un server gRPC separato nella tua applicazione che ascolta su una porta riservata a questo scopo. In questo modo puoi accedere alle tue applicazioni gRPC anche quando le porte di dati non sono accessibili a causa di problemi di rete o di configurazione errata. Ti consigliamo di esporre l'interfaccia di amministrazione solo su localhost o su un socket di dominio Unix.

I seguenti snippet di codice mostrano come creare un'interfaccia di amministrazione.

C++

In C++, utilizza questo codice per creare un'interfaccia di amministrazione:

#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());

Vai

In Go, utilizza questo codice per creare un'interfaccia di amministrazione:

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

In Java, utilizza questo codice per creare un'interfaccia di amministrazione:

import io.grpc.services.AdminInterface;

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

Python

In Python, utilizza questo codice per creare un'interfaccia di amministrazione:

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()

Utilizzare SSH per connettersi a una VM

L'esempio di wallet gRPC attiva già l'interfaccia di amministrazione. Puoi modificare la porta dell'interfaccia di amministrazione specificando il seguente flag:

 --admin-port=PORT

La porta di amministrazione predefinita è localhost:28881.

Per eseguire il debug dell'applicazione gRPC, puoi utilizzare SSH per connetterti a una delle VM che serve il servizio wallet-service. In questo modo puoi accedere a 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

Installa lo strumento grpcdebug

Per accedere all'interfaccia di amministrazione, devi disporre di un client gRPC in grado di comunicare con i servizi di amministrazione nella tua applicazione gRPC. Negli esempi seguenti, utilizzi un strumento chiamato grpcdebug che puoi scaricare e installare sulla VM o sul pod dove è in esecuzione la tua applicazione gRPC. Il repository per grpcdebug si trova all'indirizzo grpc-ecosystem/grpcdebug.

La versione minima supportata di Golang è 1.12. La guida ufficiale all'installazione di Golang è disponibile sul sito di Golang. Se stai seguendo la guida per creare una VM Linux per wallet-service, puoi installare Golang 1.16 utilizzando questi comandi:

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

Installa lo strumento grpcdebug con i seguenti comandi:

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

Ora hai accesso all'interfaccia a riga di comando grpcdebug. L'output della guida contiene informazioni sui comandi supportati:

$ 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

Per ottenere ulteriori informazioni su un determinato comando, utilizza quanto segue:

 grpcdebug <target address> [command] --help

Utilizza lo strumento grpcdebug per eseguire il debug delle applicazioni

Puoi utilizzare lo strumento grpcdebug per eseguire il debug delle applicazioni. Lo strumento grpcdebug fornisce una configurazione simile a ssh_config che supporta l'aliasing, la riscrittura del nome host e l'impostazione della sicurezza della connessione (non sicura/TLS). Per saperne di più su questa funzionalità avanzata, consulta grpcdebug/Connect&Security.

Le sezioni seguenti descrivono i servizi esposti dall'interfaccia di amministrazione e come accedervi.

Utilizzare Channelz

Il servizio Channelz fornisce accesso alle informazioni di runtime sulle connessioni a diversi livelli nella libreria gRPC della tua applicazione. Puoi utilizzarlo per eseguire analisi in tempo reale delle applicazioni che potrebbero avere problemi di configurazione o di rete. I seguenti esempi presuppongono che tu abbia disegnato l'esempio di Wallet gRPC utilizzando le istruzioni riportate in Configurare la gestione avanzata del traffico con i servizi gRPC proxyless e che tu abbia fornito il seguente flag:

 --admin-port=PORT

Dopo aver inviato alcune RPC da un client di test, come mostrato in Verifica della configurazione, utilizza i seguenti comandi per accedere ai dati di Channelz per i servizi gRPC:

  1. Utilizza SSH per connetterti a una VM su cui è in esecuzione wallet-service.
  2. Configura grpcdebug per connetterti all'applicazione gRPC in esecuzione.

L'output predefinito di grpcdebug è in un formato tabella adatto alla console. Se fornisci il flag --json, l'output viene codificato come JSON.

Il comando grpcdebug channelz viene utilizzato per recuperare e presentare informazioni di debugging dal servizio Channelz. Il comando funziona sia per i client gRPC sia per i server gRPC.

Per i client gRPC, il comando grpcdebug channelz channels fornisce un elenco dei canali esistenti e alcune informazioni di base:

$ 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 hai bisogno di ulteriori informazioni su un determinato canale, puoi utilizzare grpcdebug channelz channel [CHANNEL_ID] per esaminare le informazioni dettagliate relative al canale. L'identificatore del canale può essere l'ID canale o l'indirizzo di destinazione, se esiste un solo indirizzo di destinazione. Un canale gRPC può contenere più sottocanali, ovvero l'astrazione di gRPC su una connessione 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

Puoi anche esaminare le informazioni dettagliate di un sottocanale:

$ 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

Puoi recuperare informazioni sulle socket 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

Sul lato server, puoi utilizzare Channelz per controllare lo stato della tua applicazione server. Ad esempio, puoi ottenere l'elenco dei server utilizzando il 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

Per ottenere ulteriori informazioni su un server specifico, utilizza il comando grpcdebug channelz server. Puoi ispezionare le socket del server nello stesso modo in cui esamini quelle del client.

$ 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

Utilizzare il servizio di rilevamento dello stato del client

L'API Client Status Discovery Service (CSDS) fa parte delle API xDS. In un'applicazione gRPC, il servizio CSDS fornisce l'accesso alla configurazione (chiamata anche configurazione xDS) che riceve da Cloud Service Mesh. In questo modo, potrai identificare e risolvere i problemi relativi alla configurazione della tua mesh.

Gli esempi riportati di seguito presuppongono che tu abbia eseguito il deployment dell'esempio di Wallet gRPC utilizzando le istruzioni riportate in Configurare la gestione avanzata del traffico con i servizi gRPC proxyless.

Per utilizzare CSDS per esaminare la configurazione:

  1. Utilizza SSH per connetterti a una VM su cui è in esecuzione wallet-service. Segui le istruzioni riportate in Utilizzare SSH per connettersi a una VM.
  2. Esegui il client grpcdebug.

Per avere una panoramica dello stato della configurazione, esegui il seguente comando:

grpcdebug localhost:28881 xds status

Vedrai risultati simili ai seguenti:

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

Puoi trovare la definizione dello stato di configurazione nella documentazione del proxy Envoy. In breve, lo stato di una risorsa xDS è REQUESTED, DOES_NOT_EXIST, ACKED o NACKED.

Per ottenere un dump della configurazione xDS non elaborata, esegui il seguente comando:

grpcdebug localhost:28881 xds config

Viene visualizzato un elenco JSON dell'oggetto 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 l'output della configurazione non elaborata è troppo dettagliato, grpcdebug ti consente di filtrare in base a tipi specifici di xDS. Ad esempio:

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

Puoi anche eseguire il dump della configurazione di più tipi di xDS contemporaneamente:

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

Passaggi successivi