Grpc-03-选择器

  1. 什么是Grpc
  2. 为什么我们要使用grpc
  3. 优点有哪些

resolver、balancer、picker之间的关系

从图中可以看出 grpc 客户端与服务端的通信主要有两个阶段

  1. 建立链接阶段
  2. 帧传输阶段

这其中存在三个主要的功能接口

  • 解析器 resolver 负责根据域名解析地址

  • 平衡器 balancer 负责根据地址构建对应连接

  • 选择器 picker 负责在发送的时候选择合适的连接

在第一阶段建立链接的过程中,主要通过 解析器与平衡器构建链接;在第二阶段发送过程中通过选择器从准备好的连接中选择合适的连接进行帧的传输

根据负载均衡器的位置不同,可以分为

  • 根据作用的位置可以分为客户端负载均衡器、服务端负载均衡器
  • 根据部署的方式可以分为 集中式LB(Proxy Model)、进程内LB(Balancing-aware Client)、独立LB进程(External Load Balancing Service)

独立LB与集中式LB的区别是,独立LB不在进程内部,但是是伴随着进程的,类似SideCar模式。

grpc-go 的中的负载均衡器(选择器),其实是一种 进程内LB,它的核心功能就是:根据规则选择合适的子链接进行消息发送

整体流程

实际应用

代码路径:balancer\balancer.go

选择器定义了一个 Picker 的接口,按照备注

  1. Pick 函数用于发送RPC消息的连接以及相关信息
  2. Pick 函数不应该被阻塞,如果有任何I/O、阻塞、一定时间开销的操作,那么应该返回 ErrNoSubConnAvailable的内部错误,那么它将重复调用(注意:它会一致重复!)直到Picker更新 ClientConn.UpdateState
  3. 如果返回了其他错误
    • 如果返回一个状态错误来源于 status\status.go,那么 rpc将停止并返回这个错误
    • 如果是其他错误,那么等待的rpc调用将继续调用,不需要等待的rpc调用将立即停止并返回这个错误以及 状态 Code 为 Unavailable
1
2
3
type Picker interface {
Pick(info PickInfo) (PickResult, error)
}

选择器执行失败的逻辑处理,代码路径:picker_wrapper.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
for {
//...
pickResult, err := p.Pick(info)

if err != nil {
if err == balancer.ErrNoSubConnAvailable {
continue
}
if _, ok := status.FromError(err); ok {
// Status error: end the RPC unconditionally with this status.
return nil, nil, dropError{error: err}
}
// For all other errors, wait for ready RPCs should block and other
// RPCs should fail with unavailable.
if !failfast {
lastPickErr = err
continue
}
return nil, nil, status.Error(codes.Unavailable, err.Error())
}
//...
}

这个 failfast 是通过 serviceconfig.MethodConfig 中的 WaitForReady 控制,可在初始化连接配置

1
grpc.WithDefaultServiceConfig(`{"methodConfig": [{"waitForReady": true}]}`)

实际应用

PickFirst

pickFirst 是 grpc-go 内置的选择器,它的作用是从链接中选择第一个已经建立好的链接给流使用

代码路径:pickfirst.go

首先,看下选择器 pickfirstBalancer 结构体

1
2
3
4
5
type pickfirstBalancer struct {
state connectivity.State
cc balancer.ClientConn
sc balancer.SubConn
}
  • connectivity.State 表示选择器的状态
  • balancer.ClientConn 负责子链接 SubConn 的创建、移除。更新客户端链接 ClientConn 的状态。由 ccBalancerWrapper结构实现
  • balancer.SubConn 主要负责向 grpc 服务发起链接

其次,pickfirstBalancer 其实实现了平衡器构建接口,也就是说,通过 pickfirstBalancer 可以构建一个平衡器

参考文档

  1. https://zhuanlan.zhihu.com/p/377860784