brpc channel init 过程梳理

背景

Channel 是 brpc 中的重要概念,抽象了 client 和 server 之间的通信细节,在每次发起一个 rpc call 时,需要一个 channel 实体进行通信。本文将尝试对 brpc Channel::Init 的过程进行梳理。

用法

从下面官方的例子可以看出,用户在使用 Channel 时需要进行初始化,可以在这个过程中对默认参数进行覆盖。

1
2
3
4
brpc::ChannelOptions options;  // 包含了默认值
options.xxx = yyy;
...
channel.Init(..., &options);

目前 brpc 提供了 3 中签名的 Channel::Init 接口,签名如下。

1
2
3
4
// src/brpc/channel.h
int Init(butil::EndPoint server_addr_and_port, const ChannelOptions* options);
int Init(const char* server_addr_and_port, const ChannelOptions* options);
int Init(const char* server_addr, int port, const ChannelOptions* options);

实现细节

  1. 实现细节大同小异,区别是第一个不判断当前 channel 的管理方式,默认使用单链接,第一个不检查 PROTOCOL。
  2. 主要逻辑在 InitSingle 中实现,其主要逻辑如下:
    1. 调用 GlobalInitializeOrDie 进行全局初始化,主要工作包括注册信号处理器、注册协议处理器
    2. 调用 InitChannelOptionsChannelOptions 设置默认值,如果用户设置了值,则会覆盖默认值
      1. 检查 connection_type,优先级为 SINGLE > POOLED > SHORT
      2. 查找 protocol index,如果 protocol 不支持则失败
      3. Normalize connection group,即进行一次 stirng trim
    3. 检查端口有效性
    4. 计算 Channel Signature,即对 ChannelOptions 计算 hash 值
    5. 如果 Channel 使用 SSL,调用 CreateSocketSSLContext,计算 SSLContext
    6. 调用 SocketMapKey 创建连接的唯一标识
    7. 调用 SocketMapInsert 根据 ChannelOptions 创建 Channel 并放到 ChannelMap
      1. 最终依赖 SocketMap::Insert,其逻辑如下
        1. 根据 channel key 从 map 中查询连接,如果能找到则直接返回,说明其他线程可能已经创建好了 channel
        2. 调用 SocketCreator::CreateSocket 新建 socket
        3. 根据 socket 创建 SocketUniquePtr 保证 socket 总能访问到
        4. 将 socket 放到 map 中
        5. 如果需要在 bvar 中记录 socket_map,则更新 bvar,由 FLAGS_show_socketmap_in_vars 控制