XRPC:一个能写进简历的 C++ 高性能分布式 RPC 框架,QPS 13万+

发布时间:2026/6/26 2:34:56

XRPC:一个能写进简历的 C++ 高性能分布式 RPC 框架,QPS 13万+ 先说一个让很多人沉默的问题你在简历上写过熟悉 RPC 框架吗如果面试官接着问RPC 调用的完整链路是什么从客户端发起请求到服务端返回响应中间每一步发生了什么能流畅回答的人大概不到 10%。能进一步回答连接池为什么能把 P99 延迟从 10ms 压到 0.2ms的人更是凤毛麟角。这不是他们不努力而是他们用的学习路径从一开始就走偏了——调过 gRPC改过 GitHub 上别人的 RPC demo但从来没有亲手造过一个。今天这篇文章就是为想造一个的人写的。为什么不直接学 gRPC / brpc / srpc这个问题我被问过很多次答案很直接。gRPC 的核心 C 实现超过50 万行。brpc 也在10 万行以上。你打开任何一个文件迎接你的是层层宏定义、平台兼容代码、协议扩展点……光理清模块依赖关系就要花一周。更关键的是这些项目展示的是一个经历了多年打磨的成品。你看不到 RpcChannel 的异步调用链是怎么一步步设计出来的看不到 protobuf 反射 dispatch 是在哪个阶段接进去的看不到连接池的 acquire/release 接口为什么要这样设计更看不到 msgid 透传是怎么从协议层一路贯穿到链路追踪的。这些从0到1的过程是任何成品代码都给不了你的东西。XRPC4700 行25 天从空文件夹到完整 RPC 框架这个项目叫XRPC基于我之前实现的 ReactorX 事件驱动引擎和 NetCore 网络库向上构建完整的 RPC 框架层。核心代码4700 行含测试与压测代码总计约8600 行25 天完整教学每天增量实现每天结束都能编译运行。先看架构全貌先看压测数据同一台机器连接池开启1000 次顺序 RPC 调用P50 延迟 0.061 ms P95 延迟 0.163 ms P99 延迟 0.226 ms ← 不到 0.23ms 最大延迟 0.357 ms 顺序 QPS 12,821 次/秒 延迟分布 0.1ms ████████████████████████████████████ 821次 (82.1%) 0.2ms ███████ 162次 (16.2%) 0.3ms 13次 (1.3%)扩展性曲线连接池开启 vs 关闭并发 32 workers并发数 │ 无连接池 QPS P99 │ 有连接池 QPS P99 加速比 ────────┼────────────────────────┼─────────────────────────────── 1 │ 2,564 1.02ms │ 12,500 0.20ms 4.9x 4 │ 7,692 8.62ms │ 50,000 0.20ms 6.5x 16 │ 12,698 10.18ms │ 123,077 0.21ms 9.7x 32 │ 17,778 7.28ms │ 133,333 0.46ms 7.5x连接池开启32 并发时 QPS 达到 13.3 万P99 仍在 0.5ms 以内。没有连接池的版本P99 高达 710ms这就是每次 RPC 新建 TCP 连接的代价——每次都要经历三次握手在高并发下彻底成为瓶颈。这个对比是 Day 12 压测专题的核心内容数据是真实跑出来的不是估算。三行启动服务端五行发起调用接口设计参考 gRPC 风格学完之后切换任何主流 RPC 框架几乎无缝衔接// ══ 第一步实现业务方法 ══════════════════════════════ class OrderServiceImpl : public order::Order { public: void makeOrder(google::protobuf::RpcController*, const order::MakeOrderRequest* req, order::MakeOrderResponse* rsp, google::protobuf::Closure* done) override { rsp-set_order_id(ORD- std::to_string(seq_)); rsp-set_total_amount(req-quantity() * 99.0); rsp-set_ret_code(0); done-Run(); // 框架在此编码响应并回包 } private: std::atomicint seq_{1000}; }; // ══ 第二步3 行启动 RpcServer ═══════════════════════ EventLoop loop; RpcServer server(loop, InetAddress(9090), /*io_threads*/4); server.registerService(std::make_sharedOrderServiceImpl()); server.start(); loop.loop(); // ══ 第三步客户端异步调用 ══════════════════════════ auto ctrl std::make_sharedRpcController(); ctrl-SetTimeout(3000); // per-call 超时 3s auto closure std::make_sharedRpcClosure([]() { printf(订单号: %s 金额: %.2f 元\n, rsp-order_id().c_str(), rsp-total_amount()); }); auto channel std::make_sharedRpcChannel( client_loop, InetAddress(127.0.0.1, 9090)); channel-Init(ctrl, req, rsp, closure); order::Order_Stub stub(channel.get()); stub.makeOrder(ctrl.get(), req.get(), rsp.get(), closure.get()); // ══ 进阶连接池零额外代码切换══════════════════ ConnectionPool pool(InetAddress(127.0.0.1, 9090), /*pool_size*/8); pool.start(); auto channel std::make_sharedRpcChannel(pool); // 只改这一行 // 其余调用代码完全相同框架自动取用空闲连接并归还从无池切换到有池只需改一行——RpcChannel的构造参数从EventLoop地址换成ConnectionPool其余调用代码一字不改。25 天你会亲手构建什么整个教程分三个递进阶段每一阶段结束都有完整可运行的交付物。第一阶段ReactorX 事件驱动引擎Day 1–5一切性能的根基。Day 1 实现 epoll 封装Poller和事件分发抽象Channel第一次运行时你会看到键盘输入被事件循环捕获——这是事件驱动从概念变成代码的一刻Day 2 构建 EventLoop实现 One Loop Per Thread 框架到这天结束你已经能写一个真正跑起来的 echo serverDay 3 接入基于 timerfd 的定时器Day 4 实现 eventfd 跨线程唤醒和线程池Day 5 做压测QPS 可达 50 万第二阶段NetCore 高性能网络库Day 6–10在事件驱动引擎之上搭建完整的网络抽象层。Day 6 封装 Socket RAIIDay 7 实现 Acceptor 连接接受器含 idleFd 技巧防止 fd 耗尽Day 8 实现三区域自动扩容 Bufferreadv 系统调用一次读取所有数据Day 9 是整个网络库最难也最精华的一天——TcpConnection 的四状态机、shared_ptr weak_ptr tie机制防止野指针和提前析构、高水位回调控制发送缓冲Day 10 把所有组件粘合成 Multi-Reactor 架构的 TcpServer主 Reactor 只接连接Sub Reactor 池负责 IORound-Robin 负载均衡三十行代码启动支持数万并发的多线程服务器第三阶段RocketRPC 框架层Day 11–25

相关新闻