프록시리스 gRPC 애플리케이션의 관측 가능성

마이크로서비스 모니터링 가능성 도구는 Cloud Service Mesh의 gRPC 워크로드를 포함하여 Google Cloud에 배포된 gRPC 워크로드에서 Cloud Monitoring, Cloud Logging, Cloud Trace의 원격 분석 데이터를 수집하고 나타내기 위해 애플리케이션을 계측하는 기능을 제공합니다.

gRPC 클라이언트와 서버는 OpenCensus와 통합되어 측정항목 및 trace를 Trace 및 Monitoring을 포함한 다양한 백엔드로 내보냅니다. 이 작업은 다음 gRPC 언어를 사용하여 수행할 수 있습니다.

  • C++
  • Go
  • 자바

마이크로서비스 관측 가능성 개요를 읽은 후 마이크로서비스 관측 가능성 설정의 안내에 따라 다음에 대한 gRPC 워크로드를 계측합니다.

다음 태스크에 대해 이 문서의 안내를 따르세요.

Trace에서 trace 보기

설정 프로세스를 완료하면 계측된 gRPC 클라이언트 및 서버가 Trace에 trace를 보냅니다. Google Cloud 콘솔의 Trace 개요 페이지에 최근 trace 목록이 표시됩니다. 개별 trace를 선택하면 다음 섹션에 설명된 것과 비슷하게 트래픽 분석 정보를 볼 수 있습니다.

Envoy 프록시와 Trace 호환성

Envoy의 관측 가능성에 설명된 대로 Cloud Service Mesh 및 Envoy 프록시로 Trace에 trace를 내보낼 때는 Envoy의 OpenCensus 추적기 구성이 사용됩니다. 이 구성은 프록시리스 gRPC 애플리케이션 및 Envoy 프록시에서 내보낸 trace가 서비스 메시 내에서 완전히 호환되도록 만듭니다. 프록시리스 gRPC와의 호환성을 위해 Envoy 부트스트랩은 해당 OpenCensusConfigGRPC_TRACE_BIN trace 형식을 포함하도록 trace 컨텍스트를 구성해야 합니다. 예를 들면 다음과 같습니다.

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

관리 인터페이스 노출

일부 경우에는 측정항목 및 trace 데이터로 문제를 해결하는 데 충분하지 않습니다. 애플리케이션에서 gRPC 라이브러리의 구성 및 런타임 상태를 확인해야 할 수 있습니다. 이 정보에는 리졸버 정보, 피어 연결 상태, 채널의 RPC 통계, Cloud Service Mesh에서 수신된 구성이 포함됩니다.

이러한 정보를 얻기 위해 gRPC 애플리케이션은 특정 포트로 관리 인터페이스를 노출할 수 있습니다. 그런 후 서비스 구성 방법과 실행 방법을 확인하기 위해 애플리케이션을 쿼리할 수 있습니다. 이 섹션에서는 지원되는 각 언어로 작성된 애플리케이션에 대해 관리 인터페이스를 구성하는 방법에 대한 안내를 찾을 수 있습니다.

애플리케이션에서 이 목적으로 예약된 포트로 리슨하는 개별 gRPC 서버를 빌드하는 것이 좋습니다. 이렇게 하면 잘못된 구성 또는 네트워크 문제로 인해 데이터 포트에 액세스할 수 없을 때에도 gRPC 애플리케이션에 액세스할 수 있습니다. localhost 또는 Unix 도메인 소켓에서만 관리 인터페이스를 노출하는 것이 좋습니다.

다음 코드 스니펫은 관리 인터페이스를 만드는 방법을 보여줍니다.

C++

C++에서 이 코드를 사용하여 관리 인터페이스를 만듭니다.

#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

Go에서 이 코드를 사용하여 관리 인터페이스를 만듭니다.

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에서 이 코드를 사용하여 관리 인터페이스를 만듭니다.

import io.grpc.services.AdminInterface;

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

Python

Python에서 이 코드를 사용하여 관리 인터페이스를 만듭니다.

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

SSH를 사용하여 VM에 연결

gRPC 월렛 예시는 이미 관리자 인터페이스를 사용 설정합니다. 다음 플래그를 제공하여 관리 인터페이스 포트를 변경할 수 있습니다.

 --admin-port=PORT

기본 관리 포트는 localhost:28881입니다.

gRPC 애플리케이션을 디버깅하려면 SSH를 사용하여 wallet-service를 제공하는 VM 중 하나에 연결합니다. 그러면 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

grpcdebug 도구를 설치합니다.

관리 인터페이스에 액세스하려면 gRPC 애플리케이션에서 관리 서비스와 통신할 수 있는 gRPC 클라이언트가 필요합니다. 다음 예시에서는 gRPC 애플리케이션이 실행되는 VM 또는 Pod에서 다운로드하고 설치할 수 있는 grpcdebug라는 도구를 사용합니다. grpcdebug를 위한 저장소는 grpc-ecosystem/grpcdebug에 있습니다.

최소 지원 Golang 버전은 1.12입니다. 공식 Golang 설치 가이드는 Golang 사이트에 있습니다. 가이드에 따라 wallet-service용 Linux VM을 만드는 경우 다음 명령어를 사용하여 Golang 1.16을 설치할 수 있습니다.

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

다음 명령어를 사용하여 grpcdebug 도구를 설치합니다.

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

이제 grpcdebug 명령줄 인터페이스에 액세스할 수 있습니다. 도움말 출력에는 지원되는 명령어에 대한 정보가 포함되어 있습니다.

$ 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

특정 명령어에 대한 자세한 내용을 보려면 다음을 사용합니다.

 grpcdebug <target address> [command] --help

grpcdebug 도구를 사용하여 애플리케이션 디버그

grpcdebug 도구를 사용하여 애플리케이션을 디버깅할 수 있습니다. grpcdebug 도구는 ssh_config와 비슷한 구성을 제공합니다. 이 구성은 별칭 지정, 호스트 이름 다시 쓰기, 연결 보안 설정(비보안/TLS)을 지원합니다. 이 고급 기능에 대한 자세한 내용은 grpcdebug/Connect&Security를 참조하세요.

다음 섹션에서는 관리 인터페이스에서 노출되는 서비스 및 여기에 액세스하는 방법을 설명합니다.

Channelz 사용

Channelz 서비스는 애플리케이션의 gRPC 라이브러리에서 서로 다른 수준의 연결에 대한 런타임 정보에 액세스할 수 있게 해줍니다. 구성 또는 네트워크 관련 문제가 있을 수 있는 애플리케이션의 실시간 분석을 위해 이 서비스를 사용할 수 있습니다. 다음 예시에서는 프록시리스 gRPC 서비스로 고급 트래픽 관리 구성의 안내에 따라 gRPC 월렛 예시를 배포했고 다음 플래그를 제공했다고 가정합니다.

 --admin-port=PORT

구성 확인에 표시된 대로 테스트 클라이언트에서 일부 RPC를 전송한 후 다음 명령어를 사용하여 gRPC 서비스에 대해 Channelz 데이터에 액세스합니다.

  1. SSH를 사용하여 wallet-service를 실행하는 VM에 연결합니다.
  2. 실행되는 gRPC 애플리케이션에 연결하도록 grpcdebug를 설정합니다.

grpcdebug의 기본 출력은 Console에 친화적인 테이블 형식입니다. --json 플래그를 제공하면 출력이 JSON으로 인코딩됩니다.

grpcdebug channelz 명령어는 Channelz 서비스에서 디버깅 정보를 가져오고 제공하기 위해 사용됩니다. 이 명령어는 gRPC 클라이언트 및 gRPC 서버 모두에 작동합니다.

gRPC 클라이언트에 대해 grpcdebug channelz channels 명령어는 기존 채널 및 일부 기본 정보 목록을 제공합니다.

$ 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

특정 채널에 대해 추가 정보가 필요하면 grpcdebug channelz channel [CHANNEL_ID]를 사용하여 해당 채널의 세부 정보를 검사할 수 있습니다. 채널 식별자는 채널 ID 또는 대상 주소(대상 주소 하나만 있는 경우)일 수 있습니다. gRPC 채널은 TCP 연결 위의 gRPC 추상화인 여러 하위 채널을 포함할 수 있습니다.

$ 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

또한 하위 채널에 대해 세부 정보를 검사할 수도 있습니다.

$ 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

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

서버 측에서 Channelz를 사용하여 서버 애플리케이션 상태를 검사할 수 있습니다. 예를 들어 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

특정 서버에 대해 자세한 정보를 확인하려면 grpcdebug channelz server 명령어를 사용합니다. 클라이언트 소켓을 검사하는 것과 동일한 방법으로 서버 소켓을 검사할 수 있습니다.

$ 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

클라이언트 상태 검색 서비스 사용

클라이언트 상태 검색 서비스(CSDS) API는 xDS API의 일부입니다. gRPC 애플리케이션에서 CSDS 서비스는 Cloud Service Mesh에서 수신하는 구성(xDS 구성이라고도 부름)에 대한 액세스를 제공합니다. 이렇게 하면 메시에서 구성 관련 문제를 식별하고 해결할 수 있습니다.

다음 예시에서는 프록시리스 gRPC 서비스로 고급 트래픽 관리 구성의 안내에 따라 gRPC 월렛 예시를 배포했다고 가정합니다.

CSDS를 사용하여 구성을 검사하려면 다음 안내를 따르세요.

  1. SSH를 사용하여 wallet-service를 실행하는 VM에 연결합니다. SSH를 사용하여 VM에 연결의 안내를 따르세요.
  2. grpcdebug 클라이언트를 실행합니다.

구성 상태 개요를 가져오려면 다음 명령어를 실행합니다.

grpcdebug localhost:28881 xds status

다음과 비슷한 결과가 표시됩니다.

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

Envoy 프록시 문서에서 구성 상태에 대한 정의를 찾을 수 있습니다. 간단히 말해서 xDS 리소스의 상태는 REQUESTED, DOES_NOT_EXIST, ACKED, NACKED 중 하나입니다.

원시 xDS 구성 덤프를 가져오려면 다음 명령어를 실행합니다.

grpcdebug localhost:28881 xds config

PerXdsConfig 객체의 JSON 목록이 표시됩니다.

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

원시 구성 출력이 너무 상세하면 다음 예시와 같이 grpcdebug를 사용하여 특정 xDS 유형을 기준으로 필터링할 수 있습니다.

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

또한 여러 xDS 유형의 구성을 동시에 덤프할 수도 있습니다.

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

다음 단계