RPC 系列(三十七):brpc 的负载均衡

上游一般通过命名服务发现所有的下游节点,并通过多种负载均衡方法把流量分配给下游节点。当下游节点出现问题时,它可能会被隔离以提高负载均衡的效率。被隔离的节点会定期被健康检查,成功后重新加入正常节点。理解「命名服务 + 负载均衡 + 健康检查」这套组合,是理解 brpc 客户端流量分配的第一步。

命名服务:NamingService

在 brpc 中,NamingService 用于获得服务名对应的所有节点。一个直观的做法是定期调用一个函数以获取最新的节点列表,但这会带来一定的延时(定期调用的周期一般在若干秒左右),作为通用接口不太合适;特别是当命名服务提供事件通知时(比如 zk),这个特性没有被利用。所以我们反转了控制权:不是我们调用用户函数,而是用户在获得列表后调用我们的接口,对应 NamingServiceActions。当然我们还是得启动进行这一过程的函数,对应 NamingService::RunNamingService。下面以三个实现解释这套方式。

如果用户需要建立这些对象仍然是不够方便的,因为总是需要一些工厂代码根据配置项建立不同的对象。鉴于此,我们把工厂类做进了框架,并且是非常方便的形式:

"protocol://service-name"

e.g.
bns://<node-name>            # baidu naming service
file://<file-path>           # load addresses from the file
list://addr1,addr2,...       # use the addresses separated by comma
http://<url>                 # Domain Naming Service, aka DNS.

这套方式是可扩展的,实现了新的 NamingService 后在 global.cpp 中依葫芦画瓢注册一下就行了,如下图所示:

NamingService 在 global.cpp 中的注册代码

看到这些熟悉的字符串格式,容易联想到 ftp://、zk://、galileo:// 等等都是可以支持的。用户在新建 Channel 时传入这类 NamingService 描述,并能把这些描述写在各类配置文件中。

负载均衡:LoadBalancer

brpc 中,LoadBalancer 从多个服务节点中选择一个节点,目前的实现包括 rr、wrr、random、la、c_murmurhash、c_md5、_dynpart 等。

LoadBalancer 最重要的是如何让不同线程中的负载均衡不互斥,解决这个问题的技术是 DoublyBufferedData。

和 NamingService 类似,我们使用字符串来指代一个 load balancer,在 global.cpp 中注册:

LoadBalancer 在 global.cpp 中的注册代码(rr、wrr、random、la 等)

健康检查

对于那些无法连接却仍在 NamingService 中的节点,brpc 会定期连接它们,成功后对应的 Socket 将被“复活”,并可能被 LoadBalancer 选择上,这个过程就是健康检查。

注意:被健康检查或在 LoadBalancer 中的节点一定在 NamingService 中。换句话说,只要一个节点不从 NamingService 删除,它要么是正常的(会被 LoadBalancer 选上),要么在做健康检查。

传统的做法是使用一个线程做所有连接的健康检查,brpc 简化了这个过程:为需要的连接动态创建一个 bthread 专门做健康检查(Socket::HealthCheckThread)。这个线程的生命周期被对应连接管理。具体来说,当 Socket 被 SetFailed 后,健康检查线程就可能启动(如果 SocketOptions.health_check_interval 为正数的话)。

系列导航


   转载规则


《RPC 系列(三十七):brpc 的负载均衡》 由 吴杭沉 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
RPC 系列(三十八):lalb 自适应负载均衡 RPC 系列(三十八):lalb 自适应负载均衡
LALB 全称 Locality-aware load balancing,是一个能把请求及时、自动地送到延时最低的下游的负载均衡算法,特别适合混合部署环境。该算法产生自 DP 系统,现已加入 brpc。 为什么需要 LALB最常见的分流算
2024-05-21
下一篇 
RPC 系列(三十六):brpc 的组合通道 RPC 系列(三十六):brpc 的组合通道
随着服务规模的增大,对下游的访问流程会越来越复杂,其中往往包含多个同时发起的 RPC 或有复杂的层次结构。但这类代码的多线程陷阱很多,用户可能写出了 bug 也不自知,复现和调试也比较困难。而且实现要么只能支持同步的情况,要么得为异步重写一
2024-05-07
  目录