生产环境运行gRPC服务的挑战

为什么要使用gRPC?

在云原生的背景下,微服务大行其道。拆分的服务越来越细粒度,相对于之前的单体架构设计,服务之间通信的质量成为影响整体服务质量的一个重要环节。

此外现在的研发体系,很少只存在一种语言,往往是多语言。此时,解决多语言交互也是一个必须解决的问题。

gRPC (gRPC Remote Procedure Calls) 是Google发起的一个开源远程过程调用 (Remote procedure call) 系统。该系统基于 HTTP/2 协议传输,使用Protocol Buffers 作为接口描述语言

其他功能:

  • 认证( authentication)
  • 双向(bidirectional streaming)
  • 流控制(flow control)
  • 超时(timeouts)

最常见的应用场景是:

  • 微服务框架下,多种语言服务之间的高效交互。
  • 将手机服务、浏览器连接至后台
  • 产生高效的客户端库

但是运行gRPC服务也带给我们一些挑战,大多数是由于HTTP/2 复用链接。

gRPC带来的挑战

gRPC只是一个RPC通信框架,并不是一个服务治理框架。尤其在云原生的环境下,比如kubernetes中,由于资源紧张被驱逐,或是弹性伸缩等原因,客户端如何能及时感知到新增的server,以及剔除掉销毁的资源实例是一个挑战。由于HTTP/2 复用链接,如何解决负载均衡的问题也是另外一个挑战。

gRPC的负载均衡可以分为客户端负载均衡和代理负载均衡。

下面我们讲下我们实际使用过程中一些方案。

解决方案 1: 基于envoy的ingress controller

该方案又可称为边缘ingress。因为数据层envoy通过daemonset的方式部署到集群中,这样相当于每个node节点上部署了一个代理。边缘部署的方式,满足了高可用的要求。

假如A服务需要访问B服务,那么创建B服务的ingress,访问域名为http://b.service.com

这种方案相当于代理的方式解决负载均衡。服务注册和发现利用了k8s原生的服务发现能力。

该方案的缺点是,一个envoy要处理node节点上所有的流量,可能会因为某个服务的流量问题,影响了其他的服务。

解决方案 2: gRPC client

访问方需要集成对应语言的gRPC client。

利用了client 的客户端负载均衡的能力。不过这种方案,需要能够获取到B服务可用的server列表。

如何实现服务注册和发现那?

我们可以为B服务,创建一个Headless service,然后访问b.default.cluster.local ,coredns 会返回可用的Pod列表。

此时,将b.default.cluster.local 配置到gRPC client,客户端自动会通过dns,返回可用列表,用于客户端负载均衡。

该方案缺点是客户端引入了sdk,增加服务的复杂性。

解决方案 3: 将envoy 以 Sidecar 的模式部署

将envoy以Sidercar的模式部署,结合了前两种方案的优势,客户端代码不用引入非业务逻辑的代码,每个sidecar 只处理本client的流量逻辑。

结论

除了负载均衡和服务发现,我们还需要实现优雅退出,因为不管是dns服务发现,还是k8s原生服务发现,均有一定的延迟。

此时我们可以简单利用Pod生命周期的pre-stop钩子。

解决方案1和解决方案3,除了解决了负载均衡的问题,还能通过envoy 暴露出来的metrics和access log,增加了服务的可观察性。

当然最终的解决方案,是一个完整的service mesh方案。**

你可能感兴趣的:(kubernetes,k8s,微服务,grpc)