11

Kubernetes中的gRPC服务如何实现load balancing

 3 years ago
source link: https://zhuanlan.zhihu.com/p/336676373
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Kubernetes中的gRPC服务如何实现load balancing

专注kubernetes,istio等云原生

对于应用程序开发人员来说,gRPC是一种越来越普遍的选择。与诸如JSON-over-HTTP之类的替代协议相比,gRPC可以提供一些显着的好处,包括大幅降低(反序列化)成本,自动类型检查,格式化的API和更少的TCP管理开销。

v2-b92cf8aef0055be44e0b3a701c2fdbfc_720w.jpg

但是gRPC建立在HTTP/2之上,并且HTTP/2设计为具有单个长期TCP连接,所有请求都在该TCP连接上进行多路复用(多个请求可以在同一时间在同一连接上处于活动状态)。 但是这也意味着 gRPC 需要特殊的 load balancing。

本文主要介绍4种解决方案实现部署在Kubernetes中的gRPC服务的load balancing。

1)客户端lb + Name Resolver + Headless Service

该解决方案实现的是客户端负载均衡。实现gRPC客户端负载平衡需要两个主要组件: name resolverload balancing policy

v2-79282aa24643084bbffcd8b714b78f49_720w.jpg

当gRPC客户端想要与gRPC服务器进行交互时,它首先尝试通过向 resolver 发出名称解析请求来解析服务器名称,解析程序返回已解析IP地址的列表。

第二部分是负载平衡策略。 比如gRPC-Go库中的两个内置策略是roundrobin和grpclb策略。grpclb策略通常与外部负载均衡器一起使用。还有一个base策略,通常用于构建更复杂的选择算法。 对于解析器返回的每个非负载均衡器地址,负载均衡策略都会创建一个到该地址的新子连接。然后,该策略返回一个选择器,该选择器为客户端提供一个接口,以检索用于进行RPC调用的子连接。

默认gRPC 使用 dns 作为其 resolver。所以我们需要为我们的应用创建Headless Service 。关于Headless Service,我们这里不作详细介绍,大家可以参阅官方文档。 创建 Headless Service 的服务,Kubernetes将在该服务的DNS条目中创建多个A记录,而每个A记录与之对应的是一个Pod IP。

2)集中式Proxy

通过集中式的代理来解决gRPC 负载均衡也是一种流行的解决方案。比如当我们的客户端处于公网,我们出于安全的考量,不可能将 server 配置为公网可访问,此时集中式LB就非常适合这种场景。

v2-2d1a8b7bf8c1f1cc19207bf7f7a82996_720w.jpg

而如果我们的服务是部署在 kubernetes 中,那么选择一个支持gRPC的Ingress Controller 就可以完美解决问题。

目前基于 Envoy 实现的 Ingress Controller 均支持gRPC的负载均衡。比如 Contour,Ambassador, Gloo等。Envoy 是一个开源应用层(第 7 层)代理,提供许多高级特性。可以可以使用它来终止 SSL/TLS 连接并将 gRPC 流量路由到适当的 Kubernetes 服务。

比如我们在生产环境就是使用Contour来解决gRPC 服务负载均衡的问题。

而如果你恰好运行在Aws上,那么你可以选择ALB ingress Controller。

该方案优势是客户端无需复杂的配置,而 ingress 又是 kubernetes 本身的概念,没有其他概念的引入。

3)Service Mesh

目前所有的Service Mesh 解决方案都支持gRPC服务。包括Istio等以Envoy作为数据面的 Mesh 解决方案和 Linkerd 等非Envoy作为数据面的Mesh。

Mesh方案本质上依旧是Proxy。和集中式Proxy对比,只是将Proxy下沉到每个Client,以Sidecar的形式存在。

该方案比较复杂,不过Mesh解决方案是一个完整的服务治理方案,可以实现除了负载均衡之外的其他功能,比如故障注入,限流,熔断等,而且具备丰富的可观察性和扩展性,以及一个零信任的网络。如果你恰好在生产环境落地了Mesh,那么该方案是你最佳的选择。

4)无代理 xds 负载均衡

xDS 本身是Envoy中的概念,现在已经发展为用于配置各种数据平面软件的标准。最新版本的gRPC已经支持 基于xDS的负载平衡,目前为止,gRPC团队增加了对C-core,Java和Go语言的支持。

在xDS API流程中,客户端使用以下主要API:

  • Listener Discovery Service (LDS): 返回监听器资源。基本上用作gRPC客户端配置的root。指向RouteConfiguration。
  • Route Discovery Service (RDS): 返回RouteConfiguration资源。提供用于填充gRPC服务配置的数据。指向集群。
  • Cluster Discovery Service (CDS): 返回集群资源。配置诸如负载平衡策略和负载报告之类的内容。指向ClusterLoadAssignment。
  • Endpoint Discovery Service (EDS): 返回ClusterLoadAssignment资源。配置一组端点(后端服务器)以实现负载均衡,并可能告诉客户端丢弃请求。

为了利用xDS负载均衡,gRPC客户端需要连接到xDS服务器。客户端需要在用于创建gRPC通道的目标URI中使用xds解析器。下图显示了API调用的顺序。

xDS服务器负责发现gRPC服务器的端点并将其传达给客户端。然后,客户端会定期请求更新。

我们使用 Envoy go-control-plane库来实现xDS server。对于部署在Kubernetes中的gRPC的服务,我们可以使用k8s client-go来发现目标EndPoints。

相对于 客户端lb + Name Resolver + Headless Service,目前xds 负载均衡支持的语言不够丰富,这是我们选择该方案时,不得不考虑的问题。

这是一种无proxy的客户端负载均衡方案。对比Mesh方案,性能更好。但是该方案初衷是作为Service Mesh 方案的一种补充,并不是用来替换Mesh。

在以下的场景中,你可以考虑使用无Proxy的方案:

  • 高性能 gRPC 应用,你不想承担引入Sidecar带来的延迟。
  • 无法部署 Sidecar 代理的环境
  • 异构服务网格

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK