有些服务通过 GRpc(100+ req/sec)调用服务 A
(10 个副本),java 生成的存根。我们没有负载平衡器,但我很好奇这两种情况下的最佳实践是什么。
客户端应该在每次调用服务 A
时构建通道,还是应该创建一次 managedChannel 直到应用关闭?
如果我为每个请求创建一个,调用会分布在 10 个副本上,但如果我只在应用程序启动时创建,所有调用都会转到同一个服务 A
副本。
另一方面,如果我在每次调用时创建,在它们空闲(默认为 30 分钟)之前不会打开数千个连接吗?
ManagedChannel managedChannel = ManagedChannelBuilder
.forAddress(host, port)
.usePlaintext()
.build()
ServiceA.newBlockingStub(managedChannel)).fooBar(...)
答案 0 :(得分:3)
ManagedChannels 应该很少创建和重用。当不再使用 ManagedChannel 时,关闭它是必不可少的。否则会泄漏。
这是一个负载平衡问题,答案取决于您的负载平衡架构。根据您的描述,您可能使用的是以下两种结构之一:
所有后端都在 DNS 中公开。客户端直接连接到后端。我称之为“暴露”
有一个 TCP 负载平衡器,客户端创建一个连接到它,平衡器将该连接扩展到后端。我称之为“隐藏”
对于这两种方法,后端设置 nettyServerBuilder.maxConnectionAge(...)
通常是客户端开始使用新后端所必需的。
在暴露的架构中,您只需要在 ManagedChannel 中配置负载均衡。这可能和使用 managedChannelBuilder.defaultLoadBalancingPolicy("round_robin")
一样简单。 round_robin
政策将与 DNS 返回的每个 IP 地址建立连接,并在这些地址之间分发 RPC。当后端因 maxConnectionAge
而断开连接时,客户端将重新解析 DNS 并建立新连接。
在隐藏架构中,如果您有许多客户端,其中每个客户端与每个后端相比都“小”,那么 maxConnectionAge
就足够了。当后端由于 maxConnectionAge
断开连接时,客户端将与负载均衡器建立新连接,负载均衡器可以选择新后端。
在隐藏架构中,如果你有“大”客户端产生的负载超过单个后端可以处理的负载,那么事情就更难了;客户端无法了解后端的数量及其状态,但后端无法自行管理负载。这里最简单的方法是创建多个通道并对其进行循环。在 Java 中,您可以将其实现为 Channel
,因此它对您的大部分代码是隐藏的。当后端由于 maxConnectionAge
断开连接时,一个通道将与负载均衡器建立新连接,负载均衡器可以选择一个新后端。这种方法的困难在于知道要制作多少个频道。具有较大客户端的隐藏架构从使用 HTTP 负载平衡而不是 TCP 负载平衡中获益良多。即使使用 HTTP 负载平衡,也可能需要使用多个托管通道,以平衡负载平衡器的负载。