gRPC 客户端负载均衡

gRPC client side load balancing

提问人:Idan 提问时间:9/23/2016 最后编辑:Abhijit SarkarIdan 更新时间:8/14/2019 访问量:13393

问:

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

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

我假设客户端正在执行某种 DNS 缓存,这导致所有调用都发送到同一台服务器。是这样吗?有没有办法禁用它并设置相同的存根客户端进行“新”调用并在每次调用时通过 DNS 获取一个新 IP?

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

python http dns kubernetes grpc

评论


答:

2赞 CJ Cullen 9/23/2016 #1

如果已创建普通 Kubernetes 服务,则该服务应具有自己的负载均衡虚拟 IP(检查是否显示服务)。如果是这种情况,DNS 缓存应该不是问题,因为单个虚拟 IP 应该在实际后端之间拆分流量。kubectl get svc your-serviceCLUSTER-IP

尝试确认您的服务确实知道您的所有后端。kubectl get endpoints your-service

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

评论

0赞 Idan 9/23/2016
服务器有一个CLUSTER_IP,当我“获取端点”时,我可以看到我拥有所有端点。仍然转到同一台服务器。我认为这可能是 gRPC 的工作方式以及它的 HTTP/2 的连接重用......
27赞 David García Quintas 9/29/2016 #2

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

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

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

LB 策略的输入是已解析地址的列表。使用 DNS 时,如果 foo.com 解析为 ,则策略将尝试与所有这些 DNS 建立连接。第一个成功连接的人将成为被选中的人,直到它断开连接。因此,“pick-first”这个名字。一个更长的名字可能是“先选择并尽可能长时间地坚持下去”,但这会导致文件名很长:)。如果/当选取的地址断开连接时,选取优先策略将移至返回下一个成功连接的地址(内部称为“连接的子通道”)(如果有)。同样,只要它保持连接状态,它就会继续选择这个连接的子通道。如果所有这些方法都失败,则调用将失败。[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 策略,即循环。此外,我们可能会考虑在该客户端配置中引入一个“随机化”位,这将在对地址进行轮询之前对地址进行随机排序,从而有效地实现您的预期。

评论

0赞 Idan 9/29/2016
感谢您的详细回答。实际上,我已经按照您的建议做了,并为每个请求创建了一个新通道(我知道效率不高)。从您的回答中,我了解到只有 dns 中的第一个 ip 会收到请求,直到它停止(没有可用连接/终止/崩溃),然后客户端才会到达第二个 ip,依此类推......是吗?
0赞 David García Quintas 9/30/2016
是的。如前所述,在更改允许选择循环而不是优先选择作为 LB 策略之前。
1赞 Ryan Chou 1/5/2017
是否有任何典型的解决方案来扩展多个 gRPC 服务器?还是客户端负载均衡?
6赞 Abhijit Sarkar 8/14/2019 #3

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

这是因为 gRPC 是基于 HTTP/2 构建的,而 HTTP/2 旨在 具有一个长期存在的 TCP 连接,所有请求都通过该连接 多路复用 — 这意味着多个请求可以在同一节点上处于活动状态 在任何时间点连接。通常,这很棒,因为它 减少连接管理的开销。但是,这也意味着 (正如你所想象的那样)连接级平衡不是很强 有用。一旦建立了连接,就没有更多的平衡了 待完成。所有请求都将固定到单个目标 Pod。

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