美文网首页大型分布式系统...原云生实践
Go 实现 gRPC 代理网关和流控功能

Go 实现 gRPC 代理网关和流控功能

作者: codeandcode | 来源:发表于2023-05-04 08:27 被阅读0次

    今天给大家推荐一个 Go 语音实现的 gRPC 代理/网关,配置简单、开箱即用。先和大家介绍一下负载原理:

    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.png

    gRPC Proxy 流程图:


    grpc-proxy-2.png

    均衡策略

    目前支持 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 列表

    gRPC 网关 - synapsor

    拉取代码后即可运行

    运行

    配置好 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 端主动断开连接 ;

    相关文章

      网友评论

        本文标题:Go 实现 gRPC 代理网关和流控功能

        本文链接:https://www.haomeiwen.com/subject/tfhxsdtx.html