? 背景
后端兩個服務 ServiceA、ServiceB,ServiceA 通過 gRPC 遠程調用 ServiceB。在 Docker Swarm 集群下每個服務部署多個副本,假設部署兩個副本,即 ServiceA 的實例為 A1 和 A2,ServiceB 的實例為 B1 和 B2。Swarm 集群內部通過 Overlay 網絡實現容器間通信,ServiceA 訪問 ServiceB 通過服務名稱來連接,即 A1 調用 ServiceB 時,會隨機調用到 B1 或者 B2;同理,A2 也是如此。
上述流程,看似合理且正常,然而實際效果是:假設 A1 連通 B1,A2 連通 B1,那么 ServiceA 的請求會一直被 B1 接收并處理,直至 TCP 連接超時,或者 B1 服務終止。gRPC 的核心概念中有 Channel ,描述 Client 與 Server 之間的連接,即 A1 與 B1 建立連接之后, Channel 會被復用。
面對這種負載不均衡的場景,我們希望 ServiceA 的每個請求能被均衡到 ServiceB 的每個實例去處理。
? GRPC 負載均衡
工作流程
- 1、Client 請求解析 server name,獲取一個或多個實際 IP 地址,例如 ServiceB 解析為 10.0.0.10、10.0.0.11
- 2、Client 實例化負載均衡策略,可選策略為
round_robin
和grpclb
。注意:如果解析程序返回的地址是均衡器地址,無論 Client 配置什么負載均衡策略,都將使用grpclb
策略。否則,會使用 Client 配置的負載均衡策略。如果未配置,則 Client 將默認選用第一個可用服務器地址的策略 - 3、負載均衡衡策略為每個服務器地址創建一個子通道
- 4、對于每個 RPC 請求,負載均衡策略決定應將 RPC 請求發送到哪個子通道(即哪個服務器)
針對上述場景,在 Swarm 集群中,我們應該選擇 dnsrr
模式,并且 gRPC 客戶端配置負載均衡策略為 round_robin
(輪訓)即可。
? 配置 Load Balance Policy
不同語言配置方式不同,以下列舉常用語言:
grpc-java 配置
ManagedChannel channel = ManagedChannelBuilder.forAddress(server.getHost(), server.getPort())
.defaultLoadBalancingPolicy("round_robin")
.usePlaintext().build();
其他語言
有待完善。。。
配置 Docker Swarm dnsrr
Docker Swarm 默認的模式是 vip
,使用 dnsrr
只需將 endpoint_mode
設置為 dnsrr
即可,相關資料:
示例:
version: '3.7'
services:
server:
image: "server:latest"
stop_grace_period: 20s
networks:
- idp_network
deploy:
replicas: 2
endpoint_mode: dnsrr
networks:
idp_network:
external: true
Spring Boot gRPC Load Balance 案例
1、獲取案例源碼
git clone https://github.com/ChinaSilence/spring-boot-starter-grpc.git
2、Install 相關包
- https://github.com/ChinaSilence/spring-boot-starter-grpc/tree/master/spring-boot-starter-grpc
- https://github.com/ChinaSilence/spring-boot-starter-grpc/tree/master/samples-facade
3、構建相關鏡像
- server: https://github.com/ChinaSilence/spring-boot-starter-grpc/tree/master/samples-server
- client: https://github.com/ChinaSilence/spring-boot-starter-grpc/tree/master/samples-client
4、初始化 Swarm 集群
docker swarm init
5、添加 Overlay 網絡
docker network create -d overlay --attachable idp_network
6、部署 gRPC server 和 client
docker stack deploy -c stack.yml grpc
在 stack.yml
文件所在路徑下執行
7、查看 server 端日志
docker service logs -f grpc_server
8、持續通過 client 發送請求,并觀察日志信息
curl http://localhost:8081/v1/user/list
從日志中可以看出,server 能均衡處理 client 的請求。