bRPC 高并发 RPC 框架实战:一次请求的旅程、bthread 原理与调优手册
【免费下载链接】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
生产环境里最折磨人的三个现象:连接数悄悄涨到几万把 fd 耗尽;p99 延迟从 5ms 突然冲到 200ms;CPU 跑满 100% 却没有多少请求被处理完。这些问题的根子往往在同一处——RPC 层的线程、连接和调度设计。bRPC 是一个用 C++ 写的工业级 RPC 框架,靠 bthread 用户态调度和 epoll 事件驱动收发,支撑搜索、存储、广告推荐这类百万级 QPS 系统。这篇文章沿一次请求的路径把它拆开讲,最后给一份按现象排查的调优清单。
从零到第一次调用:快速上手
仓库克隆下来跑通 echo 样例只需要四行命令:
git clone https://gitcode.com/GitHub_Trending/brpc/brpc cd brpc && sh config_brpc.sh --headers=/usr/include --libs=/usr/lib && make cd example/echo_c++ && make && ./echo_server & ./echo_client依赖只有 gflags、protobuf、leveldb 三样,详见 docs/cn/getting_started.md。跑通后建议直接看 docs/official.md 里的快速入门章节,Client 端核心就两个类:Channel 选地址和连接,Controller 装参数、超时、重试。
一次请求的完整旅程:逐层拆解架构
跟着一次调用走一遍,各层职责就清楚了:
- 客户端发起:业务代码填好 protobuf 请求,交给 Channel。Channel 先向命名服务(DNS、ZooKeeper、etcd 或文件列表)问"该找哪台机器",再由负载均衡算法挑一台,最后从已有连接里取一条可用的 TCP 长连接——绝大多数请求在这里零建连开销。
- 序列化与发送:消息按协议序列化(baidu_std、baidu_std over http、h2/gRPC、thrift 等都走同一套通道),追加到该连接的发送队列。epoll 通知数据就绪后,多个线程对同一 fd 的写出是 wait-free 委托的:第一个线程就地写,其余线程只挂一个写请求,不打架。
- 网络 IO 到 bthread 处理:服务端收到完整消息后,每个请求被放进一个新建的 bthread 里执行用户逻辑——不用区分"IO 线程"和"处理线程",不同连接的读取、同一连接里不同消息的解析是完全并发的,一条超大消息解不动,连累不到别人的请求。
- 响应返回:处理完的响应走同一条连接写回,客户端 bthread 被唤醒,业务代码同步取到 response。整个链路上锁极少,官方文档给出过 50 万 QPS 下框架自身几乎不产生锁竞争的压测数据。
支撑高并发的三个关键机制
bthread 用户态线程:解决"一慢拖全"
M:N 映射:成百上千个 bthread 跑在少量 pthread worker 上,worker 空了就 work-stealing 去抢别人的队列。一个 bthread 卡住只卡它自己,其他请求照跑;对使用者意味着写业务代码用同步风格即可,延迟不确定(查库、调下游)也不怕拖垮整个进程,线程数还随负载自动伸缩。
长连接与连接池:解决"建连风暴"
传统短连接每次都要三次握手加可能的 TLS 协商,QPS 上去后 fd 和 CPU 都消耗在建连上。bRPC 默认维持到目标机器的长连接并池化管理,连接断了自动重连并重试;还可以选单连接模式,把同一台后端的多个请求复用到一条 TCP 上,靠上面说的无锁写出并发。对你来说就是:连接数可控,/connections页面随时能看。
负载均衡与命名服务:解决"打爆一台"
可选策略包括 round-robin、randomized、一致性哈希(murmurhash3/md5)和 locality-aware。需要按用户 ID 路由到固定后端(缓存亲和场景)就选一致性哈希,节点增减时迁移比例最小;普通无状态服务用轮询或随机即可。策略可以按 Channel 单独配,也能自己扩展新的命名服务和算法。
性能调优手册:现象、原因、调法
CPU 跑满但没有吞吐:先看切换和热点
现象:util 接近 100%,QPS 上不去了。原因:热点函数、锁竞争,或大量 worker 卡在阻塞系统调用里,CPU 时间花在切换而非计算。调法:打开内置 CPU profiler 看火焰图,用 contention profiler 看锁;阻塞调用多就调大bthread_concurrency,但真正的解法是消除阻塞本身。
p99 长尾突刺:超时、队列与备份请求
现象:p50 正常,p99 偶发几十倍抖动。原因:个别慢请求在队列和下游等待中堆积,把同批请求一起拖慢。调法:给每层调用配紧超时;高可用场景开 backup request——RT 超过阈值就向另一台后端补发一份,谁先回来用谁,代价是重复计算,只适合幂等接口。
连接池参数怎么配
现象:后端扩容后客户端报错或延迟上升。原因:连接数上限和并发请求量不匹配,连接不够就在客户端排队。调法:按"单机 QPS × 平均 RT × 余量"估算对每台后端的并发连接需求,再定连接池大小;对同一后端只开一条连接时用单连接模式,配合 bRPC 的并发写出通常就够,别过早加连接数。
出问题时看哪里:监控、诊断与容错
排障按这个顺序走最快:
- 先看指标:bvar 把 QPS、延迟分布、各阶段耗时实时暴露成变量,
/vars页面或 Noah 曲线上一眼能看到是客户端排队还是服务端变慢。 - 再看调用链:rpcz 按采样率把请求记录进 leveldb,浏览器里能还原某次具体调用的各段耗时,配合 rpc_replay 重放流量复现问题,比 grep 日志定位快得多。
- 最后看资源:CPU、heap、contention 三个 profiler 都是 HTTP 触发的,在线服务不用停机就能抓内存分配热点和锁等待。
容错三件套按需打开:重试策略(对连接断开、超时等错误码自动重试,注意只用于幂等调用)、熔断(连续失败就快速失败,防止把坏节点打穿再雪崩到好的节点)、自适应限流(按下游 RT 自动调整放行并发,慢了就收,快了就放)。三者都是 flag 或 ServerOptions 开关,不用改框架代码。
收尾:怎么选、从哪开始
适合:C++ 技术栈、单机 QPS 过万、对 p99 敏感的中后端服务——搜索、存储、在线推理、广告推荐是它的舒适区;一个端口混跑 HTTP、gRPC、自定义协议的网关场景也很合适。不适合:主栈是 Python/Java 且没有 C++ 基建能力的团队,以及 QPS 几百以内的内部小工具,上框架的收益覆盖不了接入成本。
入门路径:docs/official.md 走一遍快速入门 → 读 docs/cn/bthread.md 和 docs/cn/load_balancing.md 理解两大机制 → 用 rpc_press 在自己的环境压一轮,按本文"现象、原因、调法"对照着调参数。工具都藏在仓库里,压测数据自己出,比看别人的 benchmark 可靠 🚀
【免费下载链接】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),仅供参考