Apache/brpc中的组合通道技术解析

Apache/brpc中的组合通道技术解析

brpc brpc是百度开发的一套高性能RPC框架,特点是支持多种协议、多语言、高并发等。适用于需要高性能RPC服务的场景。 brpc 项目地址: https://gitcode.com/gh_mirrors/brpc/brpc

概述

在现代分布式系统中,服务间的调用模式变得越来越复杂,经常需要并行发起多个RPC调用或进行分层访问。这种复杂性很容易引入多线程编程中的各种棘手问题,这些问题可能难以察觉、调试和复现。Apache/brpc项目提供的组合通道(Combo Channel)技术正是为了解决这类问题而设计的。

组合通道的必要性

传统实现方式存在以下主要问题:

  1. 同步与异步模式代码不一致:同步模式通常采用异步发起多个RPC然后分别等待的方式,而异步模式则通常使用回调加引用计数的方式实现。这种不一致性增加了代码维护成本。

  2. 取消操作难以实现:正确取消单个RPC已经不容易,更不用说组合RPC的取消操作了。但在很多场景下,取消无意义的等待是必要的。

  3. 组合性差:难以将现有实现封装为更大模式的一部分,代码复用性差。

组合通道通过将多个通道组合成一个更大的通道,封装不同的访问模式,为用户提供了一致的同步、异步和取消操作接口。

ParallelChannel详解

ParallelChannel(简称pchan)会并行地向所有内部子通道发送请求并合并响应。用户可以通过CallMapper修改请求,通过ResponseMerger合并响应。

核心特性

  • 支持同步和异步访问
  • 发起异步操作后可立即销毁
  • 支持取消操作
  • 支持超时设置

内部结构

ParallelChannel内部结构

如图所示,ParallelChannel可以包含不同类型的子通道,请求和响应可以各不相同。

添加子通道

int AddChannel(brpc::ChannelBase* sub_channel,
               ChannelOwnership ownership,
               CallMapper* call_mapper,
               ResponseMerger* response_merger);

参数说明:

  • ownership:控制ParallelChannel是否拥有子通道
  • call_mapper:请求映射器
  • response_merger:响应合并器

CallMapper详解

CallMapper负责将ParallelChannel的RPC转换为子通道的RPC。如果call_mapper为NULL,则子通道的请求就是ParallelChannel的请求。

class CallMapper {
public:
    virtual ~CallMapper();
    virtual SubCall Map(int channel_index,
                        int channel_count,
                        const google::protobuf::MethodDescriptor* method,
                        const google::protobuf::Message* request,
                        google::protobuf::Message* response) = 0;
};

特殊返回值:

  • SubCall::Bad():立即终止RPC
  • SubCall::Skip():跳过当前子通道

ResponseMerger详解

response_merger负责将所有子通道的响应合并为一个。如果为NULL,则使用默认的response->MergeFrom(*sub_response)实现。

合并结果可能值:

  • MERGED:合并成功
  • FAIL:合并失败,计入失败计数
  • FAIL_ALL:直接终止整个RPC

获取子通道控制器

const Controller* sub(int index) const;

SelectiveChannel详解

SelectiveChannel(简称schan)使用负载均衡算法选择内部的一个子通道进行访问。它主要用于机器组之间的负载均衡。

核心特性

  • 支持同步和异步访问
  • 发起异步操作后可立即销毁
  • 支持取消操作
  • 支持超时设置

使用示例

brpc::SelectiveChannel schan;
brpc::ChannelOptions schan_options;
schan_options.timeout_ms = ...;
if (schan.Init(load_balancer, &schan_options) != 0) {
    LOG(ERROR) << "Fail to init SelectiveChannel";
    return -1;
}

if (schan.AddChannel(sub_channel, NULL) != 0) {
    LOG(ERROR) << "Fail to add sub_channel";
    return -1;
}

注意事项:

  • 可以随时添加子通道
  • SelectiveChannel总是拥有子通道
  • 会覆盖子通道的超时设置

应用场景:分流到多个命名服务

当需要将流量分流到多个命名服务时,SelectiveChannel是理想选择:

  1. 服务机器分布在多个命名服务中
  2. 机器分组,需要先选择组再选择组内机器

PartitionChannel详解

PartitionChannel是ParallelChannel的特化版本,能够基于命名服务中的标签自动添加子通道。

使用步骤

  1. 实现PartitionParser:
class MyPartitionParser : public brpc::PartitionParser {
public:
    bool ParseFromTag(const std::string& tag, brpc::Partition* out) {
        // 解析标签格式如"N/M"
    }
};
  1. 初始化PartitionChannel:
brpc::PartitionChannel channel;
brpc::PartitionChannelOptions options;
options.fail_limit = 1;
if (channel.Init(num_partition_kinds, new MyPartitionParser(),
                 server_address, load_balancer, &options) != 0) {
    LOG(ERROR) << "Fail to init PartitionChannel";
    return -1;
}

DynamicPartitionChannel

当需要支持多种分区方法或平滑切换分区方案时,可以使用DynamicPartitionChannel。它会为不同的分区方法创建相应的子PartitionChannel,并根据服务器容量分配流量。

总结

Apache/brpc的组合通道技术提供了一套完整的解决方案来处理复杂的RPC调用模式:

  1. ParallelChannel适合并行发起多个RPC并合并结果的场景
  2. SelectiveChannel适合在多个子通道间做负载均衡的场景
  3. PartitionChannel适合基于标签自动分区的场景
  4. DynamicPartitionChannel支持多种分区方案和平滑迁移

这些组合通道可以相互嵌套使用,构建出更加复杂的调用模式,同时保持接口的一致性和易用性。

brpc brpc是百度开发的一套高性能RPC框架,特点是支持多种协议、多语言、高并发等。适用于需要高性能RPC服务的场景。 brpc 项目地址: https://gitcode.com/gh_mirrors/brpc/brpc

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

高慈鹃Faye

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值