我使用gRPC和Python作为kubernetes pods中的客户机/服务器。。。 我希望能够启动同一类型的多个pod(gRPC服务器),并让客户端连接到它们(随机)。
我发送了10个服务器的pod,并设置了一个“服务”来瞄准它们。然后,在客户机中,我连接到服务的DNS名称-这意味着kubernetes应该进行负载平衡,并将我定向到随机服务器pod。 实际上,客户机调用gRPC函数(运行良好),但是当我查看日志时,我发现所有调用都指向同一个服务器pod。
我假设客户端正在进行某种DNS缓存,这会导致所有调用都发送到同一个服务器。是这样吗?是否仍有禁用它并设置相同的存根客户端来进行“新”调用,并在每次调用时通过DNS获取新的ip?
我知道如果它每次都查询DNS服务器,可能会导致开销,但此时对我来说,分配负载更为重要。
如果您已经创建了vanilla Kubernetes服务,那么该服务应该有自己的负载平衡虚拟IP(检查
kubectl get svc your-service
是否显示服务的CLUSTER-IP
)。如果是这种情况,DNS缓存不应该是一个问题,因为单个虚拟IP应该在实际后端之间分割流量。尝试
kubectl get endpoints your-service
确认您的服务实际上知道您的所有后端。如果您有一个headless service,DNS查找将返回一个具有10个ip的a记录(每个pod一个)。如果你的客户总是选择A记录中的第一个IP,这也可以解释你看到的行为。
通常的K8S负载平衡对gRPC不起作用。下面的链接解释了原因。 https://kubernetes.io/blog/2018/11/07/grpc-load-balancing-on-kubernetes-without-tears/
大多数现代的入口控制器都可以处理这个问题,但它们要么是热烘箱(nginx),要么是alpha版本(traefik),要么需要最新版本的K8S(Linkerd)。您可以进行客户端负载平衡,其中可以找到Java解决方案here。
让我借此机会通过描述事情应该如何工作来回答。
客户端LB在GRPC C内核中工作的方式(所有的基础,除了java和GO滋味或GRPC)如下(权威文档可以找到{a1}):
客户端LB保持简单,并且故意“哑”。我们选择的实现复杂LB策略的方法是通过外部LB服务器(如前面的文档所述)。你不关心这个场景。相反,您只需创建一个通道,它将使用(默认值)pick firstLB策略。
LB策略的输入是已解析地址的列表。使用DNS时,如果foo.com解析为
[10.0.0.1, 10.0.0.2, 10.0.0.3, 10.0.0.4]
,则策略将尝试建立到所有这些服务器的连接。第一个成功连接的将成为所选的,直到它断开。因此就有了“先挑”这个名字。一个较长的名字可以是“先选择并尽可能长时间地坚持”,但这就形成了一个很长的文件名:)。如果/当所选的一个被断开时,pick first策略将移到返回下一个成功连接的地址(内部称为“连接的子信道”),如果有的话。再次,只要保持连接,它将继续选择此已连接的子频道。如果他们都失败了,电话就会失败。这里的问题是,DNS解析本质上是基于拉的,仅在1)通道创建时触发,2)在所选连接的子通道断开时触发。
到目前为止,一个棘手的解决方案是为每个请求创建一个新的通道(非常低效,但它会按照您的设置完成任务)。
鉴于2017年第一季度的变化(见https://github.com/grpc/grpc/issues/7818),客户可以选择不同的LB策略,即循环。此外,我们可能会考虑在客户机配置中引入一个“随机化”位,这将在对地址进行循环之前对地址进行洗牌,从而有效地实现您的意图。
相关问题 更多 >
编程相关推荐