brpc 全览:工业级 C++ RPC 框架的设计哲学、核心能力与实战入门
2026/9/14 9:59:15 网站建设 项目流程

brpc 全览:工业级 C++ RPC 框架的设计哲学、核心能力与实战入门

【免费下载链接】brpcbrpc is an Industrial-grade RPC framework using C++ Language, which is often used in high performance system such as Search, Storage, Machine learning, Advertisement, Recommendation etc. "brpc" means "better RPC".项目地址: https://gitcode.com/GitHub_Trending/brpc/brpc

brpc("better RPC")是百度内部大规模使用的工业级 RPC 框架,目前在 Apache 基金会的 brpc 仓库中以 C++ 实现开源。本文以 docs/en/overview.md 为主线,系统讲解 RPC 要解决的核心问题、brpc 的适用范围与优势,并结合仓库中的源码与示例,深入剖析其多协议支持、命名服务、负载均衡、连接管理、异步模型与高性能 IO 设计的底层原理。读完本文,你将理解 brpc 的核心抽象(Server / Channel / Controller),掌握命名服务的 URL 写法与负载均衡算法选型,并能在实战中快速搭建与访问 RPC 服务。

一、RPC 到底解决了什么问题?

互联网上的机器大多通过 TCP/IP 协议相互访问,但 TCP/IP 只保证"可靠地把二进制数据送达远端"。要在其上构建服务,还有一连串问题需要抽象:

  • 数据格式:不同机器、不同网络可能存在字节序差异,直接传输内存数据不合适;业务变化导致字段增删时,新老服务如何互通?
  • 连接复用:一个 TCP 连接能否被多个请求复用?多个请求能否同时在一个连接上发送?
  • 集群管理:如何发现并访问一个包含大量机器的集群?
  • 故障处理:连接断开时该怎么办?server 迟迟不回复时怎么办?

RPC(Remote Procedure Call,远程过程调用)把网络交互抽象为"client 访问 server 上的函数":client 发送 request 后等待,直到 server 收到、处理、回复后,client 才根据 response 继续执行。

对应地,brpc 对上述问题的回答是:

  1. 序列化交给 protobuf:用户填写protobuf::Message类型的 request,RPC 结束后从同为protobuf::Message类型的 response 中取结果。protobuf 有良好的前后兼容性,方便业务增量调整字段;HTTP 场景则广泛使用 JSON 序列化。
  2. 连接建立与复用对用户透明:用户可选择不同的连接方式——短连接(short)、连接池(pooled)、单连接(single)。
  3. 机器发现交给命名服务:可基于 DNS)。每次请求由负载均衡算法从所有机器中选一台发送,支持 round-robin、randomized、consistent-hashing(murmurhash3 或 md5)与 locality-aware。
  4. 故障处理:连接断开时 RPC 会自动重试;server 未在给定时间内回复时,client 返回超时错误。

二、RPC 的适用边界与常见质疑

RPC 适用于几乎所有网络交互场景,但它不是万能的抽象,否则就不需要 TCP/IP 层了。在绝大多数网络交互中,RPC 既能解决问题,又能隔离底层网络细节。overview 文档对三个常见质疑给出了回应:

  • "我的数据是二进制大块,protobuf 序列化太慢":首先这可能是伪命题,需要用 profiler 证明"真的慢"才算数;其次,很多协议支持在 protobuf 请求之外携带二进制数据(attachment)以绕过序列化——这正是 echo 示例 中cntl->request_attachment()cntl->response_attachment()的用途:attachment 直接走网络 wire 而不经过 protobuf 序列化。
  • "我传输的是流式数据,RPC 表达不了":brpc 中很多协议支持流式数据,包括 http 的 ProgressiveReader、h2 的 streams、streaming rpc,以及专门的流式协议 RTMP。
  • "我的场景不需要回复":简单推理可知,此时请求可丢可不丢、可处理可不处理,client 永远无法感知。即使真的不需要回复,仍建议发送最小结构体的回复——这不大会成为瓶颈,却可能是排查复杂 bug 时极有价值的线索。

三、brpc 是什么:百度内部 100 万+ 实例的工业级 RPC

brpc 是百度内部最常使用的工业级 RPC 框架,在百度内被称为 "baidu-rpc",拥有超过 1,000,000 个实例(不含 client)和上千种服务。目前开源的是 C++ 实现。

3.1 一个端口,多协议并存

用 brpc 可以搭建"一个端口同时支持多种协议"的服务,也可以访问各种类型的服务:

  • restful http/https、h2/gRPC:使用 brpc 的 http 实现比 libcurl 方便得多;也可以从其他语言通过 HTTP/h2 + JSON 访问基于 protobuf 的服务。
  • redis 与 memcached:对应 redis_client.md 和 memcache_client.md,线程安全,比官方 client 更方便、性能更好。
  • rtmp/flv/hls:用于搭建流媒体服务。
  • thrift:见 thrift.md,线程安全,比官方 client 更方便。
  • 百度内部各类协议:baidu_std、streaming_rpc、hulu_pbrpc、sofa_pbrpc、nova_pbrpc、public_pbrpc、ubrpc 以及基于 nshead 的各种协议。
  • RAFT 共识算法:基于工业级 RAFT 实现搭建高可用分布式系统,已随 braft 开源。
  • rdma 支持(文档标注为"即将开源")。

3.2 调用模型与扩展能力

  • Server 可以同步或异步处理请求。
  • Client 支持同步、异步、半同步访问,也可以用组合 channels 简化分库或并行访问。
  • 可通过 http 内置服务 调试服务,运行 cpu、heap、contention profiler。
  • 可把组织内自有协议快速加入 brpc,或定制各类组件,包括命名服务(dns、zk、etcd)与负载均衡(rr、random、consistent hashing)。

四、优势一:更友好的 API——只有三个核心类

brpc 的用户接口被刻意收敛为三个(主要的)类,分别对应 server 端、client 端和参数集合:

  • Server:服务端入口,负责添加 service、监听端口、启动服务;
  • Channel:客户端入口,代表到一台或多台服务器的通信线路;
  • Controller:Server 与 Channel 共用,方法分为三段——client-side、server-side 和 both-side methods,用于设置超时、重试、压缩、attachment、log_id 等参数。

使用 brpc 时无需关心"如何初始化 XXXManager""如何组合各种组件""XXXController 与 XXXContext 的关系"这类问题。文档以命名服务为例说明"简单的事情要简单做":在老的 RPC 实现中你可能需要复制一长段晦涩代码,而在 brpc 中只是一个 URL 字符串:

// 访问 BNS 命名服务 channel.Init("bns://node-name", ...); // 访问 DNS(域名服务) channel.Init("http://domain-name", ...); // 使用本地机器列表文件 channel.Init("file:///home/work/server.list", ...);

这一设计在源码注释中有完整定义,见 src/brpc/channel.h:

  • 命名服务:bns://<node-name>(百度命名服务)、file://<file-path>(从文件加载地址)、list://addr1,addr2,...(逗号分隔的地址列表)、http://<url>(域名服务,即 DNS);
  • 负载均衡:rr(轮询)、random(随机)、wr(加权随机)、wrr(加权轮询)、la(locality-aware)、c_murmurhash/c_md5(基于 murmurhash3 / md5 的一致性哈希);
  • load_balancer_name""nullptr时,Init(xxx, "", options)Init(xxx, options)完全等价,即把命名服务 URL 当作单点 server 地址。

4.1 实战:用 echo 示例快速上手

仓库中的 example/echo_c++/server.cpp 展示了建服务的最简流程:

brpc::Server server; example::EchoServiceImpl echo_service_impl; // 第二个参数为 SERVER_DOESNT_OWN_SERVICE,表示 service 由调用方管理生命周期 if (server.AddService(&echo_service_impl, brpc::SERVER_DOESNT_OWN_SERVICE) != 0) { LOG(ERROR) << "Fail to add service"; return -1; } brpc::ServerOptions options; options.idle_timeout_sec = FLAGS_idle_timeout_s; if (server.Start(point, &options) != 0) { // point 默认 0.0.0.0:8000 LOG(ERROR) << "Fail to start EchoServer"; return -1; } server.RunUntilAskedToQuit();

服务实现类继承EchoService(由 protobuf 生成),在Echo方法中通过brpc::ClosureGuard done_guard(done)以 RAII 方式保证done->Run()被调用——这是同步处理的标准写法;若需异步处理,可done_guard.release()并在回调中自行触发。同时示例展示了 attachment 的用法:cntl->response_attachment().append(cntl->request_attachment()),二进制数据直接走网络而不经 protobuf 序列化。

example/echo_c++/client.cpp 展示了访问服务的最简流程:

brpc::Channel channel; brpc::ChannelOptions options; options.protocol = FLAGS_protocol; // 默认 baidu_std options.connection_type = FLAGS_connection_type; // single / pooled / short options.timeout_ms = FLAGS_timeout_ms; // 超时,默认 100ms options.max_retry = FLAGS_max_retry; // 最大重试次数,默认 3 if (channel.Init(FLAGS_server.c_str(), FLAGS_load_balancer.c_str(), &options) != 0) { LOG(ERROR) << "Fail to initialize channel"; return -1; } // 用 stub 包装 channel,stub 可被多线程共享 example::EchoService_Stub stub(&channel); stub.Echo(&cntl, &request, &response, nullptr); // done 为 nullptr 时同步等待 if (!cntl.Failed()) { LOG(INFO) << response.message() << " latency=" << cntl.latency_us() << "us"; }

Channel是线程安全的,可被进程内所有线程共享;done参数为nullptr时调用会阻塞直到响应返回或出错(含超时)。客户端还展示了cntl.set_log_id()cntl.request_attachment()cntl.set_request_checksum_type()(目前仅支持 CRC32C)等参数用法。

五、优势二:让服务更可靠——可观测性与性能工程

brpc 在百度内部被广泛使用:map-reduce 服务与 table 存储、高性能计算与模型训练、各类索引与排序服务等,是经历过大规模生产考验的实现。

brpc 尤其重视开发与维护效率:

  • 通过浏览器或 curl 查看 server 内部状态;
  • 分析在线服务的 cpu 热点、内存分配 与 锁竞争;
  • 通过 bvar 统计各类指标,并通过 /vars 查看。

六、优势三:更好的延时与吞吐——源码级的设计取舍

尽管几乎所有 RPC 实现都宣称"高性能",但要在一个广泛的场景中都做到高性能仍很困难。为了统一百度内的通信架构,brpc 在性能上比一般 RPC 走得更深,overview 文档给出四个关键设计:

  1. 读与解析完全并行,不区分 IO 线程与处理线程。传统实现通常区分 "IO 线程" 与 "处理线程",并把 fd 散列到 IO 线程中:当一个 IO 线程在处理某个 fd 的大消息时,同线程的其他 fd 都被阻塞。若只有 10 个 IO 线程,一个 fd 就可能影响 10% 的 fd——这对要求 99.99% 可用性的工业级在线服务不可接受,且在多租户、fd 分布不均时更糟。brpc 中,不同 fd 的读取完全并发,同一个 fd 上不同消息的解析也并发,解析一个巨大的 protobuf message 不会影响同一 client 的其他消息。详见 io.md。
  2. 写出高度并发。多个线程同时向同一个 fd 写出时(单连接场景常见),第一个线程在原线程直接写出,其他线程以 wait-free。
  3. 尽量少的锁。为处理请求创建 bthread、设置超时、根据回复找到 RPC 上下文、记录性能计数器都高度并发。即使服务跑到 50 万+ QPS,也很少能在 contention profiler 中看到框架引入的锁竞争。
  4. 线程数按负载自动调节。传统服务器需要依据下游延迟调整线程数,否则吞吐受损。brpc 中每个请求运行在一个新建的 bthread 中,请求结束 bthread 即结束,因此天然随负载自动调节线程数。

brpc 与其他实现的性能对比见 benchmark。

七、延伸阅读

  • 客户端全参数与调用方式:client.md
  • 服务端全参数与异步服务:server.md
  • 连接管理细节:connections.md、io.md
  • 负载均衡与命名服务:load_balancing.md、consistent_hashing.md、lalb.md
  • 协议接入与扩展:new_protocol.md、baidu_std.md
  • 可观测性:builtin_service.md、bvar.md、vars.md、cpu_profiler.md、heap_profiler.md、contention_profiler.md
  • 构建与入门:getting_started.md、benchmark.md

【免费下载链接】brpcbrpc is an Industrial-grade RPC framework using C++ Language, which is often used in high performance system such as Search, Storage, Machine learning, Advertisement, Recommendation etc. "brpc" means "better RPC".项目地址: https://gitcode.com/GitHub_Trending/brpc/brpc

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询