配置使用无代理 gRPC 服务的高级流量管理
此配置适用于预览版客户,但我们不建议新 Cloud Service Mesh 用户采用此配置。如需了解详情,请参阅 Cloud Service Mesh 服务路由概览。
本文档介绍了如何使用以下流量管理功能配置 Cloud Service Mesh:
- 路由匹配
- 流量拆分
- 熔断
- 故障注入
- 流时长上限
- 重试
- 会话亲和性
- 离群值检测
- 局部负载均衡
虽然本文档重点介绍在 Compute Engine 上使用无代理 gRPC 设置高级流量管理,但在 Google Kubernetes Engine (GKE) 上使用无代理 gRPC 时也支持高级流量管理。
准备工作
在配置高级流量管理之前,请查看准备使用无代理 gRPC 服务设置 Cloud Service Mesh 中的要求。必须满足所有要求才能配置高级流量管理。
如需了解有关这些功能的概念信息,请参阅高级流量管理。
关于 gRPC Wallet 示例
为了说明这些功能,您将部署一个 gRPC Wallet 示例。在此示例中,有三个 gRPC 服务(grpc.examples.wallet.Wallet
、grpc.examples.wallet.stats.Stats
和 grpc.examples.wallet.account.Account
)部署为三个单独的应用。
如下图所示,您将创建一个 gRPC 客户端,该客户端调用 Wallet
服务来获取账号余额,并调用 Stats
服务来获取货币的价格。Wallet
服务会调用 Stats
和 Account
服务来计算余额。Stats
服务还会调用 Account
服务来获取用户信息。
在此示例中,您将部署两个版本的 Wallet
和 Stats
实现,以演示基于您配置的规则的请求路由。为了模拟服务的不同版本的构建和部署,您将使用服务器标志来更改仅构建一次的二进制文件的行为。
--port
标志指定虚拟机实例上的服务侦听的端口。--hostname_suffix
标志指定附加到响应请求的虚拟机实例主机名的值。结果值将作为hostname
元数据添加到响应中。这有助于您确定实例组中的哪个实例响应客户端请求。- 值为
true
的--premium_only
标志指定该服务是stats
服务的高级版本。 - 值为
true
的--v1_behavior
标志指定 Wallet 二进制文件充当 v1 版本。
下表展示了运行其中一个 gRPC 服务的每个虚拟机实例的这些标志的值、实例组中的实例数量以及这些实例组所属的后端服务。
后端服务 | 实例组 | 实例 | 服务器标志 |
---|---|---|---|
account |
account |
2 | --port=50053 --hostname_suffix="account"
|
stats |
stats |
2 | --port=50052 --hostname_suffix="stats" --account_server="xds:///account.grpcwallet.io"
|
stats-premium |
stats-premium |
2 | --port=50052 --hostname_suffix="stats_premium" --account_server="xds:///account.grpcwallet.io" --premium_only=true
|
wallet-v1 wallet-v1-affinity
|
wallet-v1 |
2 | --port=50051 --hostname_suffix="wallet_v1" --v1_behavior=true --account_server="xds:///account.grpcwallet.io" --stats_server="xds:///stats.grpcwallet.io"
|
wallet-v2 |
wallet-v2 |
1 | --port=50051 --hostname_suffix "wallet_v2" --account_server="xds:///account.grpcwallet.io" --stats_server="xds:///stats.grpcwallet.io"
|
部署这些服务后,您可以配置 Cloud Service Mesh 以根据下表中的路由规则将请求从测试客户端路由到这些后端服务。客户端会连接到服务的虚拟主机名,如“主机”列中所示。
主机 | 匹配规则 | 路由操作 |
---|---|---|
wallet.grpcwallet.io |
路径前缀:"/" 标头存在: "session_id" |
路由到 wallet-v1-affinity |
路径前缀:"/" 标头: {"route": "timeout"} |
设置 5 秒超时并 路由到 wallet-v2
|
|
路径前缀:"/" 标头: {"route": "fault"} |
让 50% 的请求失败并 将其余的路由到 wallet-v2
|
|
路径前缀:"/" 标头: {"membership": "premium"} |
路由到 wallet-v1 并在失败时最多重试 3 次 |
|
完整路径:/grpc.examples.wallet.Wallet/FetchBalance |
路由到:wallet-v1 :70%wallet-v2 :30%
|
|
默认 | 路由到 wallet-v1 |
|
stats.grpcwallet.io |
路径前缀:"/" 标头: {"membership": "premium"} |
路由到 stats-premium |
默认 | 路由到 stats |
|
account.grpcwallet.io |
路径前缀:"/" 标头: {"route": "account-fault"} |
让 30% 的请求失败并 将其的路由到 account
|
默认 | account |
此示例在两个现有服务之间使用 70/30 的流量分配比例。如果您要将流量拆分到网址映射之前未引用的新服务,请先将新服务添加到 weightedBackendServices
并赋予 0
权重。然后,逐步增加分配给该服务的权重。
测试客户端提供了以下选项,可让您生成相应的请求来演示流量管理功能。
选项 | 说明 |
---|---|
--watch=true |
调用流式传输方法以查看余额/价格 |
--unary_watch=true |
反复调用一元方法以查看余额/价格 |
--user=Alice |
注入标头 {"membership": "premium"} |
--user=Bob |
注入标头 {"membership": "normal"} |
--route=value |
注入标头 {"route": "value"} |
--affinity=true |
注入标头 {"session_id": "value"} |
准备本地环境
如需为这些示例设置本地环境,请运行以下命令:
更新
gcloud
二进制文件,确保您拥有最新版本:gcloud components update
下载示例代码库:
sudo apt-get install git -y
克隆示例的正确代码库:
export EXAMPLES_VERSION=v1.1.x git clone -b $EXAMPLES_VERSION --single-branch --depth=1 \ https://github.com/GoogleCloudPlatform/traffic-director-grpc-examples.git
创建和配置 Cloud Router 路由器实例
在本部分中,您将在每个区域中创建 Cloud Router 实例,并为 Cloud NAT 配置这些实例。此示例创建的虚拟机没有外部 IP 地址,但它们需要访问互联网。使用 Cloud NAT 配置 Cloud Router 可提供所需的访问权限。
gcloud
创建 Cloud Router 实例:
gcloud compute routers create nat-router-us-central1 \ --network=default \ --region=us-central1
为 Cloud NAT 配置路由器:
gcloud compute routers nats create nat-config \ --router-region=us-central1 \ --router=nat-router-us-central1 \ --nat-all-subnet-ip-ranges \ --auto-allocate-nat-external-ips
创建 gRPC 健康检查和防火墙规则
在本部分中,您将创建 gRPC 健康检查和防火墙规则,以允许 gRPC 健康检查请求到达您的网络。稍后,gRPC 健康检查会与后端服务相关联,似的它能够检查这些后端服务的后端实例的健康状况。
gcloud
创建健康检查:
gcloud compute health-checks create grpc grpcwallet-health-check \ --use-serving-port
为健康检查创建防火墙规则:
gcloud compute firewall-rules create grpcwallet-allow-health-checks \ --network default --action allow --direction INGRESS \ --source-ranges 35.191.0.0/16,130.211.0.0/22 \ --target-tags allow-health-checks \ --rules tcp:50051-50053
创建实例模板
在本部分中,您将创建一个实例模板,以部署在端口 50053
上公开的 account
gRPC 服务。
gcloud
创建实例模板:
gcloud compute instance-templates create grpcwallet-account-template \ --scopes=https://www.googleapis.com/auth/cloud-platform \ --tags=allow-health-checks \ --network-interface=no-address \ --image-family=debian-10 \ --image-project=debian-cloud \ --metadata-from-file=startup-script=<(echo "#! /bin/bash set -ex cd /root export HOME=/root sudo apt-get update -y pushd \$(mktemp -d) sudo apt-get install -y wget git wget https://dl.google.com/go/go1.16.5.linux-amd64.tar.gz sudo tar -C /usr/local -xvf go1.16.5.linux-amd64.tar.gz sudo cp /usr/local/go/bin/go /usr/bin/go popd git clone -b $EXAMPLES_VERSION --single-branch --depth=1 https://github.com/GoogleCloudPlatform/traffic-director-grpc-examples.git cd traffic-director-grpc-examples/go/account_server/ go build . sudo systemd-run ./account_server --port 50053 --hostname_suffix account")
创建代管式实例组
代管式实例组 (MIG) 根据需要使用自动扩缩功能创建新的虚拟机实例。在本部分中,您将使用在上一部分中创建的实例模板创建 MIG。
gcloud
创建实例组:
gcloud compute instance-groups managed create grpcwallet-account-mig-us-central1 \ --zone=us-central1-a \ --size=2 \ --template=grpcwallet-account-template
配置已命名端口
在本部分中,您将为 gRPC 服务配置已命名端口。已命名端口是 gRPC 服务在其中侦听请求的端口。在此示例中,已命名端口是端口 50053
。
gcloud
创建已命名端口:
gcloud compute instance-groups set-named-ports grpcwallet-account-mig-us-central1 \ --named-ports=grpcwallet-account-port:50053 \ --zone=us-central1-a
创建后端服务
在本部分中,您将创建具有 INTERNAL_SELF_MANAGED
和协议 GRPC
的负载平衡方案的全局后端服务。然后,您需要将健康检查和实例组与后端服务相关联。在此示例中,您将使用在创建代管实例组中创建的 MIG。此 MIG 运行 account
gRPC 服务。--port-name
标志中的端口是您在配置已命名端口中创建的已命名端口。
gcloud
创建后端服务并将健康检查与新的后端服务相关联。
gcloud compute backend-services create grpcwallet-account-service \ --global \ --load-balancing-scheme=INTERNAL_SELF_MANAGED \ --protocol=GRPC \ --port-name=grpcwallet-account-port \ --health-checks=grpcwallet-health-check
将代管实例组添加为后端:
gcloud compute backend-services add-backend grpcwallet-account-service \ --instance-group=grpcwallet-account-mig-us-central1 \ --instance-group-zone=us-central1-a \ --global
创建 gRPC Wallet 示例中使用的其余后端服务的步骤与上述步骤类似。您可以通过运行 Shell 脚本来创建其余服务。该脚本会部署以下后端服务:
stats
stats-premium
wallet-v1
wallet-v1-affinity
wallet-v2
运行创建额外后端服务的 Shell 脚本:
traffic-director-grpc-examples/scripts/create_service.sh go stats 50052 stats '--account_server="xds:///account.grpcwallet.io"' traffic-director-grpc-examples/scripts/create_service.sh go stats 50052 stats-premium '--account_server="xds:///account.grpcwallet.io" --premium_only=true' # This command creates wallet-v1 and wallet-v1-affinity backend services. traffic-director-grpc-examples/scripts/create_service.sh java wallet 50051 wallet-v1 '--account_server="xds:///account.grpcwallet.io" --stats_server="xds:///stats.grpcwallet.io" --v1_behavior=true' traffic-director-grpc-examples/scripts/create_service.sh java wallet 50051 wallet-v2 '--account_server="xds:///account.grpcwallet.io" --stats_server="xds:///stats.grpcwallet.io"'
创建路由规则
在本部分中,您将创建一个网址映射,用于演示各种流量管理功能。网址映射指定此示例中服务的虚拟主机名以及关联的路由规则。如需了解详情,请参阅路由规则映射。
在网址映射中,hostRules
指定示例中服务的虚拟主机名。这些是客户端在通道 URI 中用于连接到特定服务的名称。例如,为了向 account
服务发送请求,客户端会在通道 URI 中使用 xds:///account.grpcwallet.io
。在 hostRules
中,配置值为 account.grpcwallet.io
的 hosts
条目。
与 hosts
条目关联的 pathMatcher
指定包含该虚拟主机的所有路由规则的 pathMatcher
的名称。pathMatcher
配置由匹配规则和相应的操作规则组成,如关于 gRPC Wallet 示例中所述。
gcloud
创建网址映射:
export PROJECT_ID=$(gcloud config list --format 'value(core.project)') export BS_PREFIX=projects/$PROJECT_ID/global/backendServices/grpcwallet gcloud compute url-maps import grpcwallet-url-map << EOF name: grpcwallet-url-map defaultService: $BS_PREFIX-account-service hostRules: - hosts: - account.grpcwallet.io pathMatcher: grpcwallet-account-path-matcher - hosts: - stats.grpcwallet.io pathMatcher: grpcwallet-stats-path-matcher - hosts: - wallet.grpcwallet.io pathMatcher: grpcwallet-wallet-path-matcher pathMatchers: - name: grpcwallet-account-path-matcher defaultService: $BS_PREFIX-account-service routeRules: - matchRules: - prefixMatch: / headerMatches: - headerName: route exactMatch: account-fault priority: 0 routeAction: weightedBackendServices: - backendService: $BS_PREFIX-account-service weight: 100 faultInjectionPolicy: abort: httpStatus: 503 percentage: 30 - name: grpcwallet-stats-path-matcher defaultService: $BS_PREFIX-stats-service routeRules: - matchRules: - prefixMatch: / headerMatches: - headerName: membership exactMatch: premium priority: 0 service: $BS_PREFIX-stats-premium-service - name: grpcwallet-wallet-path-matcher defaultService: $BS_PREFIX-wallet-v1-service routeRules: - matchRules: - prefixMatch: / headerMatches: - headerName: session_id presentMatch: true priority: 0 routeAction: weightedBackendServices: - backendService: $BS_PREFIX-wallet-v1-affinity-service weight: 100 - matchRules: - prefixMatch: / headerMatches: - headerName: route exactMatch: timeout priority: 1 routeAction: weightedBackendServices: - backendService: $BS_PREFIX-wallet-v2-service weight: 100 maxStreamDuration: seconds: 5 - matchRules: - prefixMatch: / headerMatches: - headerName: route exactMatch: fault priority: 2 routeAction: weightedBackendServices: - backendService: $BS_PREFIX-wallet-v2-service weight: 100 faultInjectionPolicy: abort: httpStatus: 503 percentage: 50 - matchRules: - prefixMatch: / headerMatches: - headerName: membership exactMatch: premium priority: 3 routeAction: weightedBackendServices: - backendService: $BS_PREFIX-wallet-v1-service weight: 100 retryPolicy: retryConditions: - unavailable numRetries: 3 - matchRules: - fullPathMatch: /grpc.examples.wallet.Wallet/FetchBalance priority: 4 routeAction: weightedBackendServices: - backendService: $BS_PREFIX-wallet-v1-service weight: 70 - backendService: $BS_PREFIX-wallet-v2-service weight: 30 - matchRules: - prefixMatch: /grpc.examples.wallet.Wallet/ priority: 5 routeAction: weightedBackendServices: - backendService: $BS_PREFIX-wallet-v2-service weight: 100 EOF
创建目标代理和转发规则
在本部分中,您将创建目标 gRPC 代理和转发规则。
目标 gRPC 代理会引用您在上一步中创建的网址映射。--validate-for-proxyless
标志会启用配置检查,这样您就不会在无意中启用与无代理 gRPC 部署不兼容的功能。
gcloud
创建目标 gRPC 代理:
gcloud compute target-grpc-proxies create grpcwallet-proxy \ --url-map=grpcwallet-url-map \ --validate-for-proxyless
转发规则会引用您创建的目标 gRPC 代理。负载平衡方案设置为 INTERNAL_SELF_MANAGED
,以指示此转发规则会由 Cloud Service Mesh 使用。此规则必须是全局转发规则。IP 地址设置为 0.0.0.0
,因为无代理 gRPC 客户端通过向 Cloud Service Mesh 发送 LDS 请求(而不是执行 DNS 查找)来解析目标 URI 中的 hostname:port
。如需了解详情,请参阅名称解析方案。
如果目标 URI 中未指定端口,则默认值为 80
。例如,目标 URI xds:///foo.myservice:8080
与使用端口 8080
配置的转发规则匹配。在此示例中,转发规则是使用端口 80
进行配置的。
gcloud
创建转发规则:
gcloud compute forwarding-rules create grpcwallet-forwarding-rule \ --global \ --load-balancing-scheme=INTERNAL_SELF_MANAGED \ --address=0.0.0.0 \ --address-region=us-central1 \ --target-grpc-proxy=grpcwallet-proxy \ --ports=80 \ --network=default
验证配置
配置过程完成后,请通过检查 Google Cloud 控制台中的 Cloud Service Mesh 页面来验证您配置的后端服务是否可用。请确认后端服务和关联的后端报告为运行状况良好。 这可能需要几分钟。
验证路由配置
在本部分中,您将验证路由配置是否正常工作。您可以使用 grpcurl
工具测试配置。
gcloud
创建客户端虚拟机,用于运行客户端以测试服务。 您可以选择性添加
--network-interface=no-address
标志。gcloud compute instances create grpc-wallet-client \ --zone=us-central1-a \ --scopes=https://www.googleapis.com/auth/cloud-platform \ --image-family=debian-10 \ --image-project=debian-cloud \ --metadata-from-file=startup-script=<(echo '#! /bin/bash set -e export GRPC_XDS_BOOTSTRAP=/run/td-grpc-bootstrap.json # Expose bootstrap variable to SSH connections echo export GRPC_XDS_BOOTSTRAP=$GRPC_XDS_BOOTSTRAP | sudo tee /etc/profile.d/grpc-xds-bootstrap.sh # Create the bootstrap file curl -L https://storage.googleapis.com/traffic-director/td-grpc-bootstrap-0.16.0.tar.gz | tar -xz ./td-grpc-bootstrap-0.16.0/td-grpc-bootstrap | sudo tee $GRPC_XDS_BOOTSTRAP')
使用 SSH 访问虚拟机,然后运行以下命令来准备虚拟机:
export EXAMPLES_VERSION=v1.1.x sudo apt-get update sudo apt-get install git -y
运行以下命令:
git clone -b $EXAMPLES_VERSION --single-branch --depth=1 \ https://github.com/GoogleCloudPlatform/traffic-director-grpc-examples.git curl -L https://github.com/fullstorydev/grpcurl/releases/download/v1.6.1/grpcurl_1.6.1_linux_x86_64.tar.gz | tar -xz chmod +x grpcurl
为了在没有 Sidecar 代理的情况下访问服务,gRPC 客户端需要使用 xds
名称解析方案。此方案指示客户端所用的 gRPC 库使用 xDS 服务器来解析主机名。为此,您需要用到引导配置。
上一部分中的启动脚本会设置 GRPC_XDS_BOOTSTRAP
环境变量,并使用帮助程序脚本生成引导文件。所生成引导文件中 TRAFFICDIRECTOR_GCP_PROJECT_NUMBER
、TRAFFICDIRECTOR_NETWORK_NAME
和 zone 的值将从知道 Compute Engine 虚拟机实例这些详细信息的元数据服务器获取。您可以使用 -gcp-project-number
和 -vpc-network-name
选项手动将这些值提供给帮助程序脚本。
使用 grpcurl
工具验证配置
在 SSH shell 中运行以下命令,验证 wallet-service
、stats-service
和 account-service
正在运行。
./grpcurl -plaintext xds:///account.grpcwallet.io list ./grpcurl -plaintext -d '{"token": "2bd806c9"}' xds:///account.grpcwallet.io grpc.examples.wallet.account.Account/GetUserInfo ./grpcurl -plaintext -H 'authorization:2bd806c9' -H 'membership:premium' xds:///stats.grpcwallet.io grpc.examples.wallet.stats.Stats/FetchPrice ./grpcurl -plaintext -H 'authorization:2bd806c9' -H 'membership:premium' -d '{"include_balance_per_address": true}' xds:///wallet.grpcwallet.io grpc.examples.wallet.Wallet/FetchBalance
您会看到以下结果:
grpc.examples.wallet.account.Account grpc.health.v1.Health grpc.reflection.v1alpha.ServerReflection { "name": "Alice", "membership": "PREMIUM" } { "price": "10295" } { "balance": "5089953" }
使用 grpc-wallet
客户端进行验证
使用以下特定于语言的说明来验证配置。以下命令会发送多个 RPC(一些 RPC 具有额外的元数据),以显示系统根据网址映射中的匹配规则将请求路由到后端服务。该命令还会输出每个响应的虚拟机实例的主机名,以显示请求所路由到的虚拟机实例。
Java
如需使用 gRPC Java 客户端验证服务,请运行以下命令:
sudo apt-get install -y openjdk-11-jdk-headless
运行以下命令:
cd ~/traffic-director-grpc-examples/java ./gradlew installDist # This command calls 'FetchBalance' from 'wallet-service' in a loop, # to demonstrate that 'FetchBalance' gets responses from 'wallet-v1' (70%) # and 'wallet-v2' (30%). ./build/install/wallet/bin/client balance --wallet_server="xds:///wallet.grpcwallet.io" --unary_watch=true --user=Bob # This command calls the streaming RPC 'WatchBalance' from 'wallet-service'. # The RPC path matches the service prefix, so all requests are # sent to 'wallet-v2'. ./build/install/wallet/bin/client balance --wallet_server="xds:///wallet.grpcwallet.io" --watch=true --user=Bob # This command calls 'WatchPrice' from 'stats-service'. It sends the # user's membership (premium or not) in metadata. Premium requests are # all sent to 'stats-premium' and get faster responses. Alice's requests # always go to premium and Bob's go to regular. ./build/install/wallet/bin/client price --stats_server="xds:///stats.grpcwallet.io" --watch=true --user=Bob ./build/install/wallet/bin/client price --stats_server="xds:///stats.grpcwallet.io" --watch=true --user=Alice
Go
如需使用 gRPC Go 客户端验证服务,请安装 golang 或按照官方说明进行操作:
sudo apt-get install -y wget wget https://dl.google.com/go/go1.16.5.linux-amd64.tar.gz sudo tar -C /usr/local -xvf go1.16.5.linux-amd64.tar.gz sudo ln -s /usr/local/go/bin/go /usr/bin/go
运行以下命令:
cd ~/traffic-director-grpc-examples/go/wallet_client go build # This command calls 'FetchBalance' from 'wallet-service' in a loop, # to demonstrate that 'FetchBalance' gets responses from 'wallet-v1' (70%) # and 'wallet-v2' (30%). ./wallet_client balance --wallet_server="xds:///wallet.grpcwallet.io" --unary_watch --user=Bob # This command calls the streaming RPC 'WatchBalance' from 'wallet-service'. # The RPC path matches the service prefix, so all requests # are sent to 'wallet-v2'. ./wallet_client balance --wallet_server="xds:///wallet.grpcwallet.io" --watch --user=Bob # This command calls 'WatchPrice' from 'stats-service'. It sends the # user's membership (premium or not) in metadata. Premium requests are # all sent to 'stats-premium' and get faster responses. Alice's requests # always go to premium and Bob's go to regular. ./wallet_client price --stats_server="xds:///stats.grpcwallet.io" --watch --user=Bob ./wallet_client price --stats_server="xds:///stats.grpcwallet.io" --watch --user=Alice
C++
如需使用 gRPC C++ 客户端验证服务,请运行以下命令:
sudo apt-get install -y build-essential
运行以下命令:
cd ~/traffic-director-grpc-examples/cpp ../tools/bazel build :client # This command calls 'FetchBalance' from 'wallet-service' in a loop, # to demonstrate that 'FetchBalance' gets responses from 'wallet-v1' (70%) # and 'wallet-v2' (30%). ../bazel-bin/cpp/client balance --wallet_server="xds:///wallet.grpcwallet.io" --unary_watch=true --user=Bob # This command calls the streaming RPC 'WatchBalance' from 'wallet-service'. # The RPC path matches the service prefix, so all requests are sent to 'wallet-v2'. ../bazel-bin/cpp/client balance --wallet_server="xds:///wallet.grpcwallet.io" --watch=true --user=Bob # This command calls 'WatchPrice' from 'stats-service'. It sends the # user's membership (premium or not) in metadata. Premium requests are # all sent to 'stats-premium' and get faster responses. Alice's requests # always go to premium, and Bob's go to regular. ../bazel-bin/cpp/client price --stats_server="xds:///stats.grpcwallet.io" --watch=true --user=Bob ../bazel-bin/cpp/client price --stats_server="xds:///stats.grpcwallet.io" --watch=true --user=Alice
配置更高级的选项
您可以按照下面各部分中的说明配置其他高级流量路由选项。
熔断
通过熔断功能,您可以设置失败阈值以防止客户端请求导致后端服务过载。在未完成请求的数量达到您设置的上限后,客户端会停止发送其他请求,从而为您的后端服务留出恢复时间。
熔断会通过向客户端返回错误而不是让后端服务过载来防止级联故障。这样一来,您便可处理一些流量,同时为管理过载情况提供时间,例如通过自动扩缩来增加容量以应对流量高峰。
为 stats-service
创建后端服务时,create_service.sh
脚本在其配置中包含以下行:
circuitBreakers: maxRequests: 1
此设置将客户端限制为一次向 stats-service
发出一个待处理的请求。由于只有一项 wallet-v2
服务,因此会同时运行两个并发客户端客户端 WatchBalance
操作,从而导致第二个实例发生故障。
Java
运行以下命令:
cd ~/traffic-director-grpc-examples/java ./build/install/wallet/bin/client balance --wallet_server="xds:///wallet.grpcwallet.io" --watch=true --user=Bob 2>/dev/null 1>/dev/null & sleep 10 # Wait a few seconds to allow the watch to begin. ./build/install/wallet/bin/client balance --wallet_server="xds:///wallet.grpcwallet.io" --watch=true --user=Bob
输出如下所示:
io.grpc.examples.wallet.Client run INFO: Will try to run balance io.grpc.examples.wallet.Client run WARNING: RPC failed: Status{code=INTERNAL, description=RPC to stats server failed: UNAVAILABLE: Cluster max concurrent requests limit exceeded, cause=null}
发出
kill
命令:kill %%
Go
运行以下命令:
cd ~/traffic-director-grpc-examples/go/wallet_client ./wallet_client balance --wallet_server="xds:///wallet.grpcwallet.io" --watch --user=Bob 2> /dev/null 1> /dev/null & sleep 10 # Wait a few seconds to allow the watch to begin. ./wallet_client balance --wallet_server="xds:///wallet.grpcwallet.io" --watch --user=Bob
输出如下所示:
server host: error: no hostname failed to fetch balance: rpc error: code = Internal desc = RPC to stats server failed: UNAVAILABLE: Cluster max concurrent requests limit exceeded
发出
kill
命令:kill %%
C++
运行以下命令:
cd ~/traffic-director-grpc-examples/cpp ../bazel-bin/cpp/client balance --wallet_server="xds:///wallet.grpcwallet.io" --watch=true --user=Bob 2>/dev/null 1>/dev/null & sleep 10 # Wait a few seconds to allow the watch to begin. ../bazel-bin/cpp/client balance --wallet_server="xds:///wallet.grpcwallet.io" --watch=true --user=Bob
输出如下所示:
Client arguments: command: balance, wallet_server: xds:///wallet.grpcwallet.io, stats_server: localhost:18882, user: Bob, watch: 1 ,unary_watch: 0, observability_project: , route: 13: RPC to stats server failed: UNAVAILABLE: Cluster max concurrent requests limit exceeded
发出
kill
命令:kill %%
故障注入
在处理请求时故障注入会引入错误,以此模拟高延迟、服务过载、服务故障和网络分区等故障。在测试服务对模拟故障的弹性时,这项功能会非常有用。
当您之前创建 URL 映射时,您设置了故障注入政策,让发送到 wallet.grpcwallet.io
的 RPC(具有 route=fault
标头)失败 50%。
如需演示故障注入,请使用以下语言的代码。
Java
运行以下命令:
cd ~/traffic-director-grpc-examples/java ./build/install/wallet/bin/client balance --wallet_server="xds:///wallet.grpcwallet.io" --unary_watch=true --user=Bob --route=fault
输出如下所示:
server host: grpcwallet-wallet-v2-mig-us-central1-zznc total balance: 10340491 - address: 148de9c5, balance: 2549839 - address: 2e7d2c03, balance: 7790652 io.grpc.examples.wallet.Client run WARNING: RPC failed: Status{code=UNAVAILABLE, description=RPC terminated due to fault injection: HTTP status code 503, cause=null}
Go
运行以下命令:
cd ~/traffic-director-grpc-examples/go/wallet_client ./wallet_client balance --wallet_server="xds:///wallet.grpcwallet.io" --unary_watch --user=Bob --route=fault
输出如下所示:
server host: grpcwallet-wallet-v1-mig-us-central1-bm1t_wallet-v1 user: Bob, total grpc-coin balance: 10452589. - address: 2e7d2c03, balance: 7875108. - address: 148de9c5, balance: 2577481. failed to fetch balance: rpc error: code = Unavailable desc = RPC terminated due to fault injection
C++
运行以下命令:
cd ~/traffic-director-grpc-examples/cpp ../bazel-bin/cpp/client balance --wallet_server="xds:///wallet.grpcwallet.io" --unary_watch=true --user=Bob --route=fault
输出如下所示:
Client arguments: command: balance, wallet_server: xds:///wallet.grpcwallet.io, stats_server: localhost:18882, user: Bob, watch: 0 ,unary_watch: 1, observability_project: , route: fault server host: grpcwallet-wallet-v2-mig-us-central1-1lm6 user: Bob total grpc-coin balance: 10211908 - address: 148de9c5, balance: 2518132 - address: 2e7d2c03, balance: 7693776 14: Fault injected
流时长上限
流时长上限允许将超时上限应用于所有 RPC。这样可防止忘记设置截止时间或设置过度截止时间的客户端浪费服务器资源。
之前创建网址映射时,将发送到 wallet.grpcwallet.io
的 RPC(具有 route=timeout
标头)的最大流时长设置为 5 秒。
如需演示超时,我们首先停止 wallet-v2
服务。
gcloud
gcloud compute instance-groups managed resize \ --size=0 grpcwallet-wallet-v2-mig-us-central1 \ --zone=us-central1-a
以下命令会永久卡住,因为没有后端服务来处理它,并且应用未设置截止时间。
Java
运行以下命令:
cd ~/traffic-director-grpc-examples/java ./build/install/wallet/bin/client balance --wallet_server="xds:///wallet.grpcwallet.io" --watch=true --user=Bob
此命令停止响应。按 ^C 可中断此命令。
Go
运行以下命令:
cd ~/traffic-director-grpc-examples/go/wallet_client ./wallet_client balance --wallet_server="xds:///wallet.grpcwallet.io" --watch --user=Bob
此命令停止响应。按 ^C 可中断此命令。
C++
运行以下命令:
cd ~/traffic-director-grpc-examples/cpp ../bazel-bin/cpp/client balance --wallet_server="xds:///wallet.grpcwallet.io" --watch=true --user=Bob
此命令停止响应。按 ^C 可中断此命令。
但是,由于 maxStreamDuration
设置,使用 timeout
路由的以下命令将在 5 秒后失败。
Java
运行以下命令:
cd ~/traffic-director-grpc-examples/java ./build/install/wallet/bin/client balance --wallet_server="xds:///wallet.grpcwallet.io" --watch=true --user=Bob --route=timeout
输出如下所示:
io.grpc.examples.wallet.Client run WARNING: RPC failed: Status{code=DEADLINE_EXCEEDED, description=deadline exceeded after 4.999594070s. [wait_for_ready, buffered_nanos=5000553401, waiting_for_connection], cause=null}
Go
运行以下命令:
cd ~/traffic-director-grpc-examples/go/wallet_client ./wallet_client balance --wallet_server="xds:///wallet.grpcwallet.io" --watch --user=Bob --route=timeout
输出如下所示:
failed to create stream: rpc error: code = DeadlineExceeded desc = context deadline exceeded.
C++
运行以下命令:
cd ~/traffic-director-grpc-examples/cpp ../bazel-bin/cpp/client balance --wallet_server="xds:///wallet.grpcwallet.io" --watch=true --user=Bob --route=timeout
输出如下所示:
Client arguments: command: balance, wallet_server: xds:///wallet.grpcwallet.io, stats_server: localhost:18882, user: Bob, watch: 1 ,unary_watch: 0, observability_project: , route: timeout 4: Deadline Exceeded
重启 wallet-v2
服务。
gcloud
gcloud compute instance-groups managed resize \ --size=1 grpcwallet-wallet-v2-mig-us-central1 \ --zone=us-central1-a
重试
重试功能可让您的 gRPC 应用根据重试政策重试出站请求,从而提高服务可用性。在重试政策中,您可以配置应重试失败请求的条件和重试次数上限(例如,当请求失败并显示特定响应代码时)。
之前创建网址映射时,您会为对 FetchBalance
方法的 RPC(具有 membership=premium
标头)设置重试政策。此政策会重试失败且状态代码为 unavailable
的 RPC,最多重试 3 次。您还将为对 account.grpcwallet.io
的 RPC(具有 route=account-fault
标头)设置故障注入政策,这可导致从 Wallet
服务到 Account
的 RPC 失败 30%。因此,来自测试客户端的标头为 membership=normal
的 RPC 失败率为 30%,而标头为 membership=premium
的 RPC 失败率低于 1%。
如需演示重试,请使用以下语言的代码。
Java
运行以下命令:
cd ~/traffic-director-grpc-examples/java # 30% of the requests fail because Bob is a normal user. ./build/install/wallet/bin/client balance --wallet_server="xds:///wallet.grpcwallet.io" --unary_watch=true --user=Bob --route=account-fault # Less than 1% of the requests fail because Alice is a premium user. ./build/install/wallet/bin/client balance --wallet_server="xds:///wallet.grpcwallet.io" --unary_watch=true --user=Alice --route=account-fault
Go
运行以下命令:
cd ~/traffic-director-grpc-examples/go/wallet_client # 30% of the requests fail because Bob is a normal user. ./wallet_client balance --wallet_server="xds:///wallet.grpcwallet.io" --unary_watch=true --user=Bob --route=account-fault # Less than 1% of the requests fail because Alice is a premium user. ./wallet_client balance --wallet_server="xds:///wallet.grpcwallet.io" --unary_watch=true --user=Alice --route=account-fault
C++
运行以下命令:
cd ~/traffic-director-grpc-examples/cpp # 30% of the requests fail because Bob is a normal user. ../bazel-bin/cpp/client balance --wallet_server="xds:///wallet.grpcwallet.io" --unary_watch=true --user=Bob --route=account-fault # Less than 1% of the requests fail because Alice is a premium user. ../bazel-bin/cpp/client balance --wallet_server="xds:///wallet.grpcwallet.io" --unary_watch=true --user=Alice --route=account-fault
会话亲和性
只要实例运行状况良好且有可用容量,会话亲和性就会尽力尝试将具有特定特征(HTTP 标头)的请求发送到同一实例。这对于有状态应用服务器非常有用(当将特定客户端的请求发送到同一实例时(而不是例如轮询分发到不同实例),有状态应用服务器可从提高的性能和效率获益)。
创建后端服务 grpcwallet-wallet-v1-affinity-service
时,在 create_service.sh
脚本中,localityLbPolicy
设置为 ROUND_ROBIN
。在此示例中,您将应用以下配置来将 localityLbPolicy
更改为 RING_HASH
。
sessionAffinity: HEADER_FIELD localityLbPolicy: RING_HASH consistentHash: httpHeaderName: "session_id"
gcloud
保存后端服务
grpcwallet-wallet-v1-affinity-service
的配置:gcloud compute backend-services export grpcwallet-wallet-v1-affinity-service \ --destination=bs_config.yaml \ --global
更新后端服务
grpcwallet-wallet-v1-affinity-service
:project_id="$(gcloud config list --format 'value(core.project)')" backend_config=" backends: - balancingMode: UTILIZATION capacityScaler: 1.0 group: projects/${project_id}/zones/us-central1-a/instanceGroups/grpcwallet-wallet-v1-mig-us-central1 connectionDraining: drainingTimeoutSec: 0 healthChecks: - projects/${project_id}/global/healthChecks/grpcwallet-health-check loadBalancingScheme: INTERNAL_SELF_MANAGED name: grpcwallet-wallet-v1-affinity-service portName: grpcwallet-wallet-port protocol: GRPC sessionAffinity: HEADER_FIELD localityLbPolicy: RING_HASH consistentHash: httpHeaderName: session_id" gcloud compute backend-services import grpcwallet-wallet-v1-affinity-service --global <<< "${backend_config}"
如需演示会话亲和性,请使用以下语言的代码。使用 --affinity=true
标志时,客户端插入标头 session-id
,其中包含每个用户的唯一值。此值的哈希值用于向后端服务 grpcwallet-wallet-v1-affinity-service
的实例组中的特定实例发送请求。
Java
运行以下命令:
cd ~/traffic-director-grpc-examples/java # Without affinity, requests are sent to both instances. ./build/install/wallet/bin/client balance --wallet_server="xds:///wallet.grpcwallet.io" --unary_watch=true --user=Alice # With affinity, requests are sent to only one instance. ./build/install/wallet/bin/client balance --wallet_server="xds:///wallet.grpcwallet.io" --unary_watch=true --user=Alice --affinity=true
Go
运行以下命令:
cd ~/traffic-director-grpc-examples/go/wallet_client # Without affinity, requests are sent to both instances. ./wallet_client balance --wallet_server="xds:///wallet.grpcwallet.io" --unary_watch=true --user=Alice # With affinity, requests are sent to only one instance. ./wallet_client balance --wallet_server="xds:///wallet.grpcwallet.io" --unary_watch=true --user=Alice --affinity=true
C++
运行以下命令:
cd ~/traffic-director-grpc-examples/cpp # Without affinity, requests are sent to both instances. ../bazel-bin/cpp/client balance --wallet_server="xds:///wallet.grpcwallet.io" --unary_watch=true --user=Alice # With affinity, requests are sent to only one instance. ../bazel-bin/cpp/client balance --wallet_server="xds:///wallet.grpcwallet.io" --unary_watch=true --user=Alice --affinity=true
恢复后端服务 grpcwallet-wallet-v1-affinity-service
的配置。
gcloud
gcloud compute backend-services import grpcwallet-wallet-v1-affinity-service \ --source=bs_config.yaml \ --global
离群值检测
要提高服务可用性,请配置异常主机检测。通过此功能,您可以识别并临时从负载均衡池中移除运行状况不佳的主机。这些运行状况不佳的主机称为异常主机。
gRPC 会根据成功率(主机成功处理请求的频率)来评估主机。该速率会受到 gRPC 错误、HTTP 错误、超时和其他问题等失败的影响。
通过 Cloud Service Mesh 配置异常主机检测时,您可以微调 gRPC 评估主机的方式以及处理异常主机的方式。例如,您可以指定以下条件:
在 gRPC 分析可能的异常主机状态之前,主机必须收到的请求数。
主机在被视为异常主机之前偏离平均成功率的程度。
任何时候都可以从负载均衡池中移除的主机百分比上限。
异常主机从负载均衡池中排除的时长。
如需详细了解可用参数,请参阅 REST Resource: backendServices
参考文档。不过,gRPC 存在一些限制,如以下部分所述。
限制
gRPC 客户端不支持以下字段:
outlierDetection.consecutiveErrors
outlierDetection.enforcingConsecutiveErrors
outlierDetection.consecutiveGatewayFailure
outlierDetection.enforcingConsecutiveGatewayFailure
设置离群值检测
以下过程演示了如何为使用一个实例组作为其后端的服务配置异常主机检测。此过程会建立以下配置:
- 异常主机检测分析每秒运行一次。您可以使用
interval
字段配置此行为。 - 异常主机从负载均衡池中移除,时长增量为 30 秒,如下所示:
- 如果主机之前从未被移除,则只会被移除 30 秒。
- 如果之前已移除过主机,则每次移除后时间都会增加 30 秒。例如,当主机被移除第三次时,系统会将其移除 90 秒。您可以使用
baseEjectionTime
字段配置此行为。
- 如果主机在所选时间间隔(在本例中为 1 秒)内成功率低于平均值一个标准差,则被视为运行状况不佳。您可以使用
successRateStdevFactor
字段配置最大标准差。
要以这种方式配置异常主机检测,请按以下步骤操作。
gcloud
使用
gcloud compute backend-services export
命令导出grpcwallet-wallet-v2-service
后端服务配置文件:gcloud compute backend-services export grpcwallet-wallet-v2-service \ --destination=bs_config.yaml \ --global
在
bs_config.yaml
文件中,更新grpcwallet-wallet-v2-service
配置以包含异常主机检测字段:outlierDetection: interval: seconds: 1 nanos: 0 baseEjectionTime: seconds: 30 nanos: 0 successRateStdevFactor: 1000
使用
gcloud compute backend-services import
命令导入更新后的文件:gcloud compute backend-services import grpcwallet-wallet-v2-service \ --source=bs_config.yaml \ --global
局部负载均衡
如需以最高效的方式利用资源,请配置局部负载均衡。此功能通过在后端之间均匀分配客户端请求来帮助您节省资源。
配置局部负载均衡时,您可以使用下表中描述的选项。所有选项都要求配置 backendServices
资源。
选项 | 适用对象 | 相关配置字段 |
---|---|---|
使用内置政策 | 所有 gRPC 客户端 | localityLbPolicy |
使用自定义政策 | 在仅包含 gRPC 客户端的网格中,使用 gRPC 1.47 版或更高版本的 Java 客户端 | localityLbPolicies
|
定义首选政策列表 | 在仅包含 gRPC 客户端的网格中,使用 gRPC 1.47 版或更高版本的 Java 客户端 | localityLbPolicies |
您可以任意组合上述选项。但是,如果同时配置 localityLbPolicy
和 localityLbPolicies
,则 gRPC 会先尝试使用 localityLbPolicies
配置。
如果您未配置局部负载均衡,则 Cloud Service Mesh 会使用 ROUND_ROBIN
政策。
如需了解 ROUND_ROBIN
和其他内置政策,请参阅 backendServices
页面上的 localityLbPolicy
说明。
使用内置政策
如果您希望所有客户端都使用单个内置政策,则可以通过配置 localityLbPolicy
字段来选择该政策。
配置此字段时,您可以从以下政策中进行选择:
LEAST_REQUEST
(仅限 Java 客户端)RING_HASH
ROUND_ROBIN
如果并非所有客户端都可以使用同一个政策,请参阅定义首选政策列表。
gcloud
使用
gcloud compute backend-services export
命令导出grpcwallet-wallet-v2-service
后端服务配置文件:gcloud compute backend-services export grpcwallet-wallet-v2-service \ --destination=bs_config.yaml \ --global
更新导出的
bs_config.yaml
文件,在其中添加以下代码行:localityLbPolicy: -- policy name: RING_HASH
使用 gcloud compute backend-services import 命令导入更新后的文件:
gcloud compute backend-services import grpcwallet-wallet-v2-service --source=bs_config.yaml --global
使用自定义政策
在适用的情况下,您可以使用通过 gRPC 创建和部署的自定义负载均衡政策。此功能适用于使用 gRPC 1.47 版或更高版本的 Java 客户端。请仅在仅包含 gRPC 客户端的网格中使用此功能。
创建自定义政策时,以下文档可能会有所帮助:
如需使自定义政策更加复杂精密,您可以使用 Open Request Cost Aggregation (ORCA) API。利用这些 API,您可以捕获有关查询费用和服务器利用率的指标。使用这些 API 需要 gRPC 1.48.1 或更高版本。如需了解详情,请参阅 gRPC ORCA 示例。
如需了解 xDS 如何将自定义负载均衡配置传送到 gRPC,请参阅 gRPC xDS 自定义负载均衡器配置。
如需将 Cloud Service Mesh 配置为使用您的自定义政策,请使用 localityLbPolicies
字段标识该政策。
以下步骤演示了此过程。在此过程中,您将更新 grpcwallet-wallet-v2-service
后端服务的配置,以便连接到该服务的客户端使用名为 example.ExampleLoadBalancer
的自定义政策。
gcloud
使用
gcloud compute backend-services export
命令导出grpcwallet-wallet-v2-service
后端服务配置文件:gcloud compute backend-services export grpcwallet-wallet-v2-service \ --destination=bs_config.yaml \ --global
更新导出的
bs_config.yaml
文件以引用example.ExampleLoadBalancer
政策。添加以下代码行:localityLbPolicies: - customPolicy: name: example.ExampleLoadBalancer data: '{ "message": "Hello load-balancing world!" }'
使用 gcloud compute backend-services import 命令导入更新后的文件:
gcloud compute backend-services import grpcwallet-wallet-v2-service --source=bs_config.yaml --global
可选:测试负载均衡配置:
Java
cd ~/traffic-director-grpc-examples/java ./build/install/wallet/bin/client balance --wallet_server="xds:///wallet.grpcwallet.io" --watch=true --user=Bob
如果您正确配置了自定义负载均衡政策,则会看到包含在配置中的消息 ("Hello load-balancing world!")。
定义首选政策列表
如果您有多个客户端不支持单个负载均衡政策,请创建客户端可使用的政策列表。使用此选项时,如果特定客户端无法使用您的第一个首选政策,则 gRPC 会回退到列表中的下一个政策。
创建首选政策列表时,有效选项包括自定义政策和 ROUND_ROBIN
,对于 Java 客户端,还包括 LEAST_REQUEST
。您最多可以列出 10 个政策。
此功能仅适用于使用 gRPC 1.47 版或更高版本的 Java 客户端。请仅在仅包含 gRPC 客户端的网格中使用此功能。
gcloud
- 使用
gcloud compute backend-services export
命令导出grpcwallet-wallet-v2-service
后端服务配置文件:
gcloud compute backend-services export grpcwallet-wallet-v2-service \ --destination=bs_config.yaml \ --global
更新导出的
bs_config.yaml
文件以添加localityLbPolicies
字段。使用表示以下政策的条目填充它:- 无效的自定义政策 (
example.InvalidLoadBalancer
) - 有效的自定义政策 (
example.ExampleLoadBalancer
) - 支持的内置政策 (
LEAST_REQUEST
)
localityLbPolicies: - customPolicy: name: example.InvalidLoadBalancer data: '{ "message": "This load-balancing policy doesn't work!" }' - customPolicy: name: example.ExampleLoadBalancer data: '{ "message": "Hello load-balancing world!" }' - policy: name: LEAST_REQUEST
- 无效的自定义政策 (
使用 gcloud compute backend-services import 命令导入更新后的文件:
gcloud compute backend-services import grpcwallet-wallet-v2-service --source=bs_config.yaml --global
可选:测试负载均衡配置:
Java
cd ~/traffic-director-grpc-examples/java ./build/install/wallet/bin/client balance --wallet_server="xds:///wallet.grpcwallet.io" --watch=true --user=Bob
在响应中,gRPC 尝试寻找但找不到
example.InvalidLoadBalancer
。之后,它回退为使用example.ExampleLoadBalancer
,并且您会看到在配置中包含的消息 ("Hello load-balancing world!")。客户端上的 gRPC 日志记录包含一条消息,表明未找到example.InvalidLoadBalancer
。
清理资源
要清理资源,请从本地系统运行以下命令:
traffic-director-grpc-examples/scripts/cleanup.sh
禁止服务之间的流量
如果您想要阻止服务 A 和服务 B 之间的流量,并且您的部署在 GKE 上,请设置服务安全性,并使用授权政策来阻止服务之间的流量。如需查看完整说明,请参阅 Cloud Service Mesh 服务安全以及 Envoy 和无代理 gRPC 设置说明。
后续步骤
- 如需帮助解决 Cloud Service Mesh 配置问题,请参阅排查使用无代理 gRPC 的部署的问题。