使用无代理 gRPC 应用实现可观测性
微服务可观测性工具使您能够对应用进行插桩,以从 Google Cloud 上部署的 gRPC 工作负载(包括 Traffic Director 中的 gRPC 工作负载)的 Cloud Monitoring、Cloud Logging 和 Cloud Trace 中收集并呈现遥测数据。
gRPC 客户端和服务器与 OpenCensus 集成,可将指标和跟踪记录导出到各种后端,包括 Trace 和 Monitoring。您可以使用以下 gRPC 语言执行此操作:
- C++
- Go
- Java
阅读微服务可观测性概览,然后按照设置微服务可观测性中的说明对 gRPC 工作负载进行插桩处理,以便执行以下操作:
- Cloud Monitoring 和查看指标。
- Cloud Logging 和查看日志。
- Cloud Trace 并查看跟踪记录。
请按照本文档中的说明完成以下任务:
通过 Trace 查看跟踪记录
完成设置过程后,已插桩的 gRPC 客户端和服务器会向 Trace 发送跟踪记录。Google Cloud 控制台中的跟踪概览页面会显示最近的跟踪记录列表。您可以选择一条跟踪记录来查看流量明细,它会显示类似于以下部分中描述的内容。
Trace 与 Envoy 代理的兼容性
如使用 Envoy 实现可观测性中所述,通过 Traffic Director 和 Envoy 代理将跟踪记录导出到 Trace 会使用 Envoy 的 OpenCensus 跟踪器配置,这使得从无代理 gRPC 应用和 Envoy 代理导出的跟踪记录能够在服务网格中完全兼容。为了与无代理 gRPC 兼容,Envoy 引导需要配置跟踪记录上下文,以在其 OpenCensusConfig
中添加 GRPC_TRACE_BIN
跟踪记录格式。例如:
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"]
公开管理接口
有时,指标和跟踪记录数据不足以解决问题。您可能需要查看应用中 gRPC 库的配置或运行时状态。此类信息包括解析器信息、与对等端连接的状态、通道上的 RPC 统计信息,以及从 Traffic Director 收到的配置。
如需获取此类信息,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
在 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 连接到虚拟机
gRPC Wallet 示例已启用管理界面。您可以通过提供以下标志来更改管理界面端口:
--admin-port=PORT
默认管理端口为 localhost:28881
。
如需调试您的 gRPC 应用,您可以使用 SSH 连接到其中一个传送 wallet-service
的虚拟机。这样您就可以使用 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 客户端。在以下示例中,您将使用名为 grpcdebug
的工具,您可以在运行 gRPC 应用的虚拟机或 pod 上下载并安装该工具。grpcdebug
的代码库位于 grpc-ecosystem/grpcdebug。
支持的最低 Golang 版本为 1.12。官方 Golang 安装指南位于 Golang 网站上。如果您按照该指南为 wallet-service
创建 Linux 虚拟机,则可以使用以下命令安装 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 Wallet 示例,并且提供了以下标志:
--admin-port=PORT
按照验证配置中所述从测试客户端发送一些 RPC 后,可以使用以下命令访问 gRPC 服务的 Channelz 数据:
- 使用 SSH 连接到运行
wallet-service
的虚拟机。 - 设置
grpcdebug
以连接到正在运行的 gRPC 应用。
grpcdebug
的默认输出采用适合控制台的表格格式。如果提供 --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
使用客户端状态发现服务
Client Status Discovery Service (CSDS) API 是 xDS API 的一部分。在 gRPC 应用中,CSDS 服务可提供其从 Traffic Director 接收的配置(也称为 xDS 配置)的访问权限。这样,您就可以识别和解决网格中与配置相关的问题。
以下示例假设您按照使用无代理 gRPC 服务配置高级流量管理中的说明部署了 gRPC Wallet 示例。
要使用 CSDS 检查配置,请执行以下操作:
- 使用 SSH 连接到运行
wallet-service
的虚拟机。 按照使用 SSH 连接到虚拟机中的说明执行操作。 - 运行
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": [...] }
后续步骤
- 如需查找相关信息,请参阅使用 Envoy 实现可观测性。
- 如需解决在部署无代理 gRPC 服务时遇到的配置问题,请参阅排查使用无代理 gRPC 的部署的问题。