codeandcode0x / synapsor

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

synapsor

gRPC 负载均衡和反向代理

代理基本原理:

  1. 基于TCP启动一个gRPC代理服务 ;
  2. 将gRPC请求的服务拦截到转发代理的一个函数中执行 ;
  3. 接收客户端的请求,处理业务指标后转发给服务端 ;
  4. 接收服务端的响应,处理业务指标后转发给客户端 ;

gRPC的客户端将所有的请求都发给 gRPC Server Proxy,这个代理网关实现请求转发,将gRPC Client的请求流转发到gRPC 服务实现的节点上。并将服务处理结果响应返回给客户端 。

HandleStream 中 unknownService

在 gRPC 框架代码中的 HandleStream 存在两类服务,一类是已知服务 knownService, 第二类是 unknownService ;已知服务 knownService 就是 gRPC 服务端代码注册到 gRPC 框架中的服务,叫做已知服务,其他没有注册的服务叫做未知服务,这个未知服务 unknownService 就是我们实现 gRPC 服务代码的关键所在;


要实现 gRPC 服务代理,我们在创建 gRPC 服务 grpc.NewServer 时,传递一个未知服务的 Handler,将未知服务的处理进行接管,然后通过注册的这个 Handler 实现 gRPC 代理转发的逻辑.


GrpcProxyTransport 接口

GrpcProxyTransport 是自定义的 StreamDirector,将 unknownService 的请求由 GrpcProxyTransport 层处理(这里有实现比较负责的连接池 + 负载均衡 的设计),提供代理和负载的能力;

基于如上描述,gRPC 代理的原理如下:

  1. 创建 gRPC 服务时,注册一个未知服务处理器 Handler 和一个自定义的编码 Codec 编码和解码,此处使用 proto 标准的 Codec;
  2. 这个 Handle 给业务方预留一个 director 的接口,用于代理重定向转发的 gRPC 连接获取,这样 proxy 就可以通过 redirector 得到 gRPCServer 的 gRPC 连接。
  3. Proxy 接收 gRPC 客户端的连接,并使用 gRPC 的 RecvMsg 方法,接收客户端的消息请求 ;
  4. Proxy 将接收到的 gRPC 客户端消息请求,通过 SendHeader 和 SendMsg 方法发送给 gRPC 服务端 ;
  5. 同样的方法,RecvMsg 接收 gRPC 服务端的响应消息,使用 SendMsg 发送给 gRPC 客户端。

至此 gRPC 代理服务就完成了消息的转发功能,限流,权限等功能可以通过转发的功能进行拦截处理 ; 如图所示 gRPC Proxy: gRPC Proxy

gRPC Proxy 流程图: gRPC Proxy 流程图

均衡策略

目前支持 gRPC 均衡策略是:

  1. 加权随机 ;
  2. 最小连接数 ;

配置说明

proxy:
  setting:
    LISTEN_PROXY_ADDR: '0.0.0.0'
  proxy_list: 
    - PROXY_NAME: 'default'
      ENABLED: true
      POOL_ENABLED: true
      DIAL_TIMEOUT: 5             # second
      BACKOFF_MAX_DELAY: 3        # second
      KEEPALIVE_TIME: 5           # second
      KEEPALIVE_TIMEOUT: 10       # second
      REQUEST_IDLE_TIME: 10       # second
      REQUEST_MAX_LIFE: 60        # second
      REQUEST_TIMEOUT: 3          # second
      POOL_MODEL: 1               # default 0 : STRICT_MODE, 1: LOOSE_MODE
      PROXY_MODEL: 'randomWeight'       # minConn or randomWeight
      GRPC_REQUEST_REUSABLE: true # 连接是否复用
      DEFAULT_GRPC_CONN_NUM: 10   # 默认创建的连接数
      PROXY_PORT: '30880'
      GRPC_PROXY_ENDPOINTS:       # 负载的 endpoints 列表, "#" 号后面是权重
        - 172.18.160.84:30880#10
        - 172.18.160.84:30880#10
  • PROXY_NAME : 为 proxy 名称
  • ENABLED: 是否启用此 proxy
  • KEEPALIVE_TIME: 如果连接没有被激活,每隔多长时间发送 pings
  • KEEPALIVE_TIMEOUT: wait 1 second for ping ack before considering the connection dead
  • REQUEST_TIMEOUT: 请求超时设置
  • GRPC_REQUEST_REUSABLE: 是否复用连接
  • LISTEN_PROXY_ADDR: synapsor 本地监听 ip
  • DEFAULT_GRPC_CONN_NUM:建立连接的默认连接数 (会自动进行扩增)
  • EXPOSE_PROXY_PORT: synapsor 暴露的端口
  • GRPC_PROXY_ENDPOINTS: 负载的 endpoint 列表
  • PROXY_MODEL: 负载的模式(minConn:最小连接数,适用于流量控制,流式连接; randomWeight: 加权随机,适用于非流控场景)

支持多个端口负载多个 endpoint 列表

运行

配置好 proxy endpoints 后,执行下面命令 docker

docker-compose up -d

k8s

kubectl apply -f deployments/kubernetes/

FAQ

Q: received prior goaway: code: ENHANCE_YOUR_CALM, debug data: “too_many_pings”

A: grpc client 的keepalive 用来检测 client 创建的grpc channel 连接是不是可用的,如果超时,就会关掉这个channel 的连接 ; grpc server 的keepalive 用来检测 server 创建的grpc channel 连接是不是可用的,如果超时,就会关掉这个channel 的连接 ; 在这里还需要特别注意一个问题, grpc client 的keepalive 的 时间设定 需要在server 允许范围内,否则,server 会发送一个GOAWAY 消息,把和client 的连接强制关掉 。

Q: code = Cancelled desc = Cancelled on the server side A: 客户端建立连接后,超过一定时间没有发送数据 (包括 ping 数据) 会被 server 端主动断开连接 ;

About

License:MIT License