跳转到内容

负载均衡

go-zero 的 zrpc 客户端默认使用 P2C(Pick of Two Choices,二选一) 负载均衡,相较于传统轮询更能感知实例延迟。

flowchart LR
    Client -->|随机选两个实例| A[实例 A
延迟 12 ms] Client --> B[实例 B
延迟 45 ms] A -->|✓ 延迟更低,被选中| Req[发送请求] B -->|✗ 跳过| Skip[未选中]

每次发起请求时,P2C 会从候选实例中随机选取两个,然后将请求路由至负载(延迟 × 在途请求数)更低的那个。这个 O(1) 的算法解决了轮询面对”慢实例”时的热点问题。

当使用 etcd 服务发现时,P2C 负载均衡自动生效,无需任何配置:

etc/app.yaml
UserRpc:
Etcd:
Hosts: [127.0.0.1:2379]
Key: user.rpc

etcd 中每个注册的实例都会自动纳入 P2C 的候选池。

使用静态地址列表时,go-zero 使用轮询策略:

UserRpc:
Endpoints:
- 10.0.0.1:8080
- 10.0.0.2:8080
- 10.0.0.3:8080

测试或调试时,可以直接指定单个实例:

UserRpc:
Endpoints:
- 127.0.0.1:8080

在 Kubernetes 中,通常将 go-zero 服务作为 Headless Service 部署,结合 Pod DNS 地址实现均衡:

k8s/service.yaml
apiVersion: v1
kind: Service
metadata:
name: user-rpc
spec:
clusterIP: None # Headless Service
selector:
app: user-rpc
ports:
- port: 8080

然后在 go-zero 配置中直接使用 DNS 地址:

UserRpc:
Target: dns:///user-rpc.default.svc.cluster.local:8080

可通过 Prometheus 监控负载均衡效果:

指标名说明
rpc_client_requests_total各实例请求总数
rpc_client_duration_ms_bucket各实例延迟直方图

在 Grafana 中用分位数折线图对比各 Pod 的 P99 延迟,可直观看到 P2C 是否有效均摊流量。

UserRpc:
Timeout: 2000 # 单次请求超时(毫秒)
KeepaliveTime: 20000 # TCP keepalive ping 间隔(毫秒)

超时期间只要约束对应 ctx 即可;go-zero 不会自动重试(防止副作用),如需重试请在业务层实现幂等逻辑后自行封装。