当前位置: 首页 > 知识库问答 >
问题:

gRPC客户端负载平衡

邵轶
2023-03-14

我在kubernetes pods中使用带有Python的gRPC作为客户端/服务器......我希望能够启动多个相同类型的pod(gRPC服务器)并让客户端(随机)连接到它们。

我调度了10个服务器吊舱,并设置了一个“服务”来瞄准它们。然后,在客户端,我连接到服务的DNS名称——这意味着kubernetes应该进行负载平衡,并将我指向一个随机服务器pod。实际上,客户机调用gRPC函数(这很有效),但当我查看日志时,我发现所有调用都会转到同一个服务器pod。

我假设客户端正在进行某种DNS缓存,这会导致所有调用都被发送到同一服务器。是这样吗?是否要禁用它,并将同一存根客户端设置为进行“新”调用,并通过DNS在每次调用中获取新的ip?

我知道如果它每次都查询DNS服务器,我可能会导致开销,但目前分配负载对我来说更重要。

共有3个答案

百里成仁
2023-03-14

如果您已经创建了一个vanilla Kubernetes服务,该服务应该有自己的负载平衡虚拟IP(检查kubectl get svc your service是否为您的服务显示了一个CLUSTER-IP)。如果是这种情况,DNS缓存不应该是一个问题,因为单个虚拟IP应该在实际后端之间分割流量。

尝试kubectl get endpoints your service,确认您的服务确实了解您的所有后端。

如果你有一个无头服务,DNS查询将返回一个包含10个IP的a记录(每个POD一个)。如果你的客户总是选择A记录中的第一个IP,这也可以解释你看到的行为。

谢豪
2023-03-14

通常的K8S负载平衡不适用于gRPC。以下链接解释了原因。https://kubernetes.io/blog/2018/11/07/grpc-load-balancing-on-kubernetes-without-tears/

这是因为gRPC建立在HTTP/2之上,而HTTP/2被设计为具有单一的长寿命传输控制协议,所有请求都通过该协议进行多路复用——这意味着多个请求可以在任何时间点在同一连接上处于活动状态。通常情况下,这很好,因为它减少了连接管理的开销。然而,这也意味着(正如您可能想象的那样)连接级平衡不是很有用。一旦建立了连接,就无需再进行平衡了。所有请求都将固定在一个目标pod上。

大多数现代入口控制器都可以处理这一问题,但它们要么是热烘箱(nginx),要么是alpha版本(traefik),要么需要最新版本的K8S(Linkedr)。您可以进行客户端负载平衡,您可以在这里找到Java解决方案。

洪国兴
2023-03-14

让我借此机会通过描述事情应该如何运作来回答这个问题。

客户端LB在gRPC C核心(除Java和Go flavors或gRPC之外的所有基础)中的工作方式如下(权威文档可在此处找到):

客户端LB故意保持简单和“沉默”。我们选择的实现复杂LB策略的方式是通过外部LB服务器(如前述文档所述)。你不关心这种情况。相反,您只需创建一个通道,该通道将使用(默认)优先选择LB策略。

LB策略的输入是已解析地址的列表。当使用DNS时,如果是foo。com解析为[10.0.0.1、10.0.0.2、10.0.0.3、10.0.0.4],策略将尝试建立与所有这些组件的连接。第一个成功连接的将成为选中的一个,直到它断开连接。因此,这个名字叫“先选”。一个较长的名称可能是“首先选择并尽可能长时间地坚持”,但这会导致文件名非常长:)。如果/当选择的一个断开连接时,选择优先策略将转移到返回下一个成功连接的地址(内部称为“连接的子通道”),如果有的话。再一次,只要保持连接,它就会继续选择这个连接的子通道。如果所有这些都失败了,通话就会失败。

这里的问题是,本质上基于拉动的DNS解析仅在1)通道创建时和2)所选连接子通道断开时触发。

到目前为止,一个黑客解决方案是为每个请求创建一个新通道(非常低效,但考虑到您的设置,它会起到作用)。

考虑到2017年第一季度的变化(参见https://github.com/grpc/grpc/issues/7818)将允许客户选择不同的LB策略,即循环。此外,我们可能会考虑在客户端配置中引入一个“随机化”位,这将在对地址进行循环之前对其进行洗牌,从而有效地实现您的意图。

 类似资料:
  • Ribbon是一个客户端负载均衡器,它可以很好地控制HTTP和TCP客户端的行为。Feign已经使用Ribbon,所以如果您使用@FeignClient,则本节也适用。 Ribbon中的中心概念是指定客户端的概念。每个负载平衡器是组合的组合的一部分,它们一起工作以根据需要联系远程服务器,并且集合具有您将其作为应用程序开发人员(例如使用@FeignClient注释)的名称。Spring Cloud使

  • 在花了几个小时阅读Http客户机文档和源代码后,我决定在这里寻求帮助。 我有一个使用循环算法的负载均衡服务器

  • 使用Cloud Foundry功能“Polyglot”集成服务发现和通过内部路由在服务容器之间直接通信,负载平衡如何工作?Cloud Foundry是否负责负载平衡?有没有一种方法可以利用客户端负载平衡,比如在这种支持Polyglot的通信之上使用Ribbon?

  • 我一直在使用,Consul作为服务注册表,Ribbon作为负载均衡器。我目前正在使用spring-boot 2.3.10。释放。 我真的很喜欢spring-blod-feign-继承支持,在我的理解中,它允许我编写服务器端和客户端使用的单个接口。 https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-feign.

  • 我正在尝试为我的java服务器实现grpc客户端负载平衡。一台服务器运行在端口6565上,另一台服务器运行在端口7575上。两台服务器的代码是相同的,但端口除外。 现在我想为这些服务器实现客户端负载平衡。 我的ServiceRegistry类如下- 我的< code>TempNameResolver类如下所示