首页 文章

gRPC客户端负载均衡

提问于
浏览
12

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

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

我假设客户端正在进行某种DNS缓存,这会导致所有呼叫被发送到同一服务器 . 是这样的吗?无论如何要禁用它并设置相同的存根客户端进行“新”呼叫并通过DNS每次呼叫获取新的IP?

我知道如果它每次都会查询DNS服务器,我可能会产生的开销,但是分配负载对我来说更重要 .

EDIT

可能不是缓存问题......可能只是gRPC的工作方式 . HTTP / 2和持久的可重用连接 . 每次通话后有什么方法可以“断开”?

2 回答

  • 12

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

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

    客户端LB保持简单并且有意为"dumb" . 我们关注这种情况的方式 . 相反,您只是创建一个通道,它将使用(默认)先选择LB策略 .

    LB策略的输入是已解析地址的列表 . 使用DNS时,如果foo.com解析为 [10.0.0.1, 10.0.0.2, 10.0.0.3, 10.0.0.4] ,策略将尝试 Build 与所有这些连接的连接 . 成功连接的第一个将成为所选的一个,直到它断开连接 . 因此名称"pick-first" . 更长的名称可能是"pick first and stick with it for as long as possible",但这是一个非常长的文件名:) . 如果/当选择的一个断开连接时,优先选择策略将移动以返回下一个成功连接的地址(内部称为"connected subchannel"),如果有的话 . 只要它保持连接,它将再次继续选择这个连接的子通道 . 如果所有这些都失败,则呼叫将失败 .

    这里的问题是,基于内在拉取的DNS解析仅在信道创建时触发1)和在断开所选连接子信道时触发 .

    到目前为止,一个hacky解决方案是为每个请求创建一个新的通道(效率非常低,但是根据你的设置,它会做到这一点) .

    鉴于2017年第一季度的变化(见https://github.com/grpc/grpc/issues/7818)将允许客户选择不同的LB政策,即Round Robin . 此外,我们可能会考虑将"randomize"位引入该客户端配置,这将在对其进行Round-Robin之前对地址进行洗牌,从而有效地实现您的意图 .

  • 1

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

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

    如果您有headless service,DNS查找将返回包含10个IP的A记录(每个Pod一个) . 如果您的客户总是选择A记录中的第一个IP,那么这也可以解释您所看到的行为 .

相关问题