feat: implement broadcast call functionality #219
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
需求:tRPC-Cpp已将内部广播代码变更打出一个patch文件,需要同学基于这个patch,适配开源版本,并完成详细的功能验证
注意:如7天内无提交任何进展包括不限于comment \ commit \ Pull Request,则将视为同学主动放弃issue,组委会将释放issue给下一位等候者。
任务整体难度评估
将一个已有的补丁(
broadcast_call.patch
)合并到 tRPC-Cpp 主干分支,并完成功能验证,是一个 中等难度 的任务。主要挑战在于:构建环境复杂性:tRPC-Cpp 使用 Bazel 进行构建,需要提前安装 Bazel 及相关依赖(如 Protobuf、gflags、fmt 等)。如果从未构建过该项目,需要花时间准备环境并熟悉 Bazel 的用法。
补丁冲突和适配:
broadcast_call.patch
可能是基于旧版本创建的。如果主干分支发生了代码变动,应用补丁时可能出现冲突,需要了解 tRPC-Cpp 框架的代码结构来手工合并修改。框架理解:广播调用涉及 RPC 框架核心机制(例如调用类型、网络传输、多实例调用等)。需要阅读并理解补丁中涉及的模块(RPC 调用层、命名服务等),对于不了解该框架的人来说有一定门槛。不过好在你有 C++ 高并发开发和 RPC 原理经验,可以加速理解这些改动。
功能验证难度:需设计测试用例验证广播调用是否生效。这涉及启动多个服务实例、模拟广播场景并收集结果。需要一定的动手实验能力。
总体而言,此任务需要在构建环境、补丁合并、代码理解、测试验证几个方面投入时间,需要仔细规划和调试。下面将针对该任务制定一个具体的开发计划。
构建和运行 tRPC-Cpp 主干版本
开始补丁合并前,需要成功构建并运行 tRPC-Cpp 主干代码,这不仅验证环境搭建正确,也为后续应用补丁提供基础。
1. 开发环境准备:确保系统满足开发需求。使用 Linux (Ubuntu 20.04) 环境,这也是官方主要支持的环境。准备工作包括:
安装 Bazel:tRPC-Cpp 使用 Bazel 构建。
安装 JDK:Bazel 需要 Java 环境。安装 OpenJDK 8 或 11 均可。确保运行
bazel
时java
可用。安装 C++编译工具链:安装
GCC
/G++
等基本编译器工具,以及 CMake 等。安装项目依赖库:tRPC-Cpp 架构依赖若干 C++ 库。在构建源码前,应确保以下库在系统中可用或提前安装:
Protobuf:用于序列化RPC消息,需安装
protoc
编译器和相应的libprotobuf
库。gflags:命令行参数解析库,tRPC 使用其定义和解析全局标志。
fmtlib:格式化输出库,用于日志打印等。
其他依赖如 OpenSSL(若使用 SSL 通信)、absl 库等。
这些库可以通过系统包管理器安装,例如在 Ubuntu 上:
sudo apt-get install -y protobuf-compiler libprotobuf-dev libgflags-dev libfmt-dev libssl-dev
2. 获取主干代码:从 GitHub 克隆 tRPC-Cpp 仓库主干分支源码:
git clone https://github.com/trpc-group/trpc-cpp.git
cd trpc-cpp
3. 编译项目:tRPC-Cpp 提供了构建脚本,根据https://github.com/trpc-group/trpc-cpp/blob/main/docs/en/setup_env.md,首选 Bazel 构建:在项目根目录:
./run_examples.sh
4. 运行示例验证:为了确认构建的二进制正常运行,脚本
./run_examples.sh
除了一键编译,还会运行所有示例,观察示例输出验证框架功能。通过以上步骤,确认主干分支的代码能够在本地成功构建和运行,为后续合并补丁打下了基础。
编译过程中遇到的问题与解决
根据 bazel 的报错信息:
undefined reference to 'SSL_...'
表明:#include <openssl/ssl.h>
),libssl.so
和libcrypto.so
)。tRPC-Cpp 的 SSL 模块需要显式声明对 OpenSSL 的依赖。从错误看,Bazel 在构建目标时未自动链接 OpenSSL。
排查
third_party/com_github_openssl_openssl/openssl.BUILD
文件中,显式添加 OpenSSL 依赖trpc/transport/common/ssl/BUILD
文件中的依赖引用正确的目标名称修改 OpenSSL BUILD 文件
打开
third_party/com_github_openssl_openssl/openssl.BUILD
文件,将目标名称从libssl
和libcrypto
改为ssl
和crypto
:更新 SSL BUILD 文件中的依赖
确保
trpc/transport/common/ssl/BUILD
文件中的依赖引用正确的目标名称:检查 WORKSPACE 配置
确保 WORKSPACE 文件中正确引用了 OpenSSL 仓库:
总结
通过以上修改,Bazel 正确找到了 OpenSSL 目标并解决了链接问题,编译运行example成功。
通过以上步骤,确认了主干分支的代码能够在本地成功构建和运行,为后续合并补丁打下了基础。
tRPC-Cpp 广播调用功能落地实录
目录
1. 分析需求
2. 分析 patch 文件
rpc_service_proxy.h/cc
:新增广播接口service_proxy.h/cc
:辅助方法BUILD
:新增依赖3. 分析项目结构
理解顺序:
接口层 (RpcServiceProxy) → 基类 (ServiceProxy) → 运行时 (future / coroutine) → 传输层 (transport)
4. 框架代码的修改
4.1 新增广播接口(声明)
4.2 同步广播核心实现(Fiber + Future 双模式)
4.3 异步广播实现(WhenAll 聚合)
4.4 辅助函数实现(路由信息 + 子 Context)
4.5 BUILD 依赖补齐
5. 开发过程中涉及的基础知识
std::tuple
、std::any
、智能指针cc_library / cc_binary / deps
写法6. 开发中遇到的问题 & 解决手段
corrupt patch at line 30
future_utility.h: No such file
'TrpcSelectorInfo' has not been declared
#include "trpc/naming/common/common_defs.h"
SetIp
不存在SetAddr(host, port)
TrpcNaming
未声明trpc::naming::SelectBatch
invalid initialization of reference
SelectBatch(selector, ...)
传引用而非指针std::any
冲突7. 编译了哪些关键文件 & 配置改了什么
trpc/client/BUILD
:新增 4 条依赖BUILD
:exports_files(["test_broadcast.cc"])
test_broadcast.cc
8. 运行示例 & 功能验证
8.1 示例代码
8.2 编译 & 运行
$ bazel run //trpc/client:broadcast_test Testing broadcast call functionality... Broadcast call interface is available and compiles successfully! This means the broadcast functionality has been successfully integrated.
8.3 正确性证明思路
rsp.size()==3
9. 项目仍存在的问题
当前广播功能 / 框架 仍存在的问题
trpc_cpp_plugin
仍只为单播 RPC 生成代码;用户需手写Broadcast*Invoke
调用gen_hdr.cc / gen_src.cc
,在每个 RPC Stub 处自动生成三种广播接口;避免人工漏写/写错模板参数Matcher
与std::any
模板推导冲突导致service_proxy_test
编译失败#define GTEST_SKIP_(...)
规避2、将
std::any
换成自定义Any
SetCalleeSetName / SetNamespace
等过期接口wrk
+ 自写 echo-server,分别测单播 vs 广播吞吐 & 延迟;关注 Fiber 版本的 CPU 利用率vector<EndpointResult>{code,msg,endpoint}
;便于上层 UI / 日志解析BroadcastStreamInvoke
:一次性建多个 stream,WhenAny 聚合 Reader/WriterProxyStatistics
中新增广播维度指标:broadcast_success_total
,broadcast_fail_total
,broadcast_avg_latency_ms
ClientContext
、循环设置超时BroadcastContextBuilder().timeout(1000).func("echo")
减少样板代码NoncontiguousBuffer
;响应合并时按需复制SetClientContextForBroadcast
时生成 子 Span,并在返回时汇聚redis_service_proxy_test
仍未通过helloworld
服务- 写脚本校验
rsp.size()==3
、内容一致- 引入 CI 工作流
阶段性目标(可做 Issue 拆分)
10. 任务体验后的收获
当我第一次看到这个 tRPC-Cpp 广播调用的任务时,内心既兴奋又忐忑。作为一个还在学习 C++ 的大学生,能够参与腾讯这样的顶级开源项目,对我来说是一次难得的机会。现在回想整个开发过程,内心充满了感激。
这次项目让我真正理解了什么是"企业级代码"。以前在学校写的都是小打小闹的练习,但这次接触到的 tRPC-Cpp 框架,让我看到了真正的工程化代码应该是什么样子。
通过看到
BroadcastUnaryInvoke
这样的泛型接口设计,了解了模板编程的深度应用。我才明白为什么 C++ 被称为"零成本抽象"的语言。每个模板参数都经过精心设计,既保证了类型安全,又提供了极致的性能。Fiber 协程和 Future 异步编程,这种并发编程的实际应用实践让我受益匪浅。这两种并发模型的选择让我理解了不同场景下的最优解。特别是看到
FiberLatch
和WhenAll
这样的并发原语,我才真正体会到现代 C++ 并发编程的优雅。网络编程很复杂,服务发现、负载均衡、错误处理,这些概念在书本上看起来很简单,但真正实现起来需要考虑的细节之多,让我对网络编程有了更深的理解。
工程实践的重要一课
版本控制的重要性在这次项目中体现得淋漓尽致。从最初的 patch 应用失败,到手动逐文件修改,再到最终的正确提交,每一步都让我学会了如何更好地使用 Git。特别是 Fork + PR 的工作流程,让我理解了开源协作的标准模式。
要构建一个系统很复杂。Bazel 这样的现代构建工具,虽然学习曲线陡峭,但一旦掌握,就能体会到它的强大。依赖管理、编译优化、测试集成,每一个环节都体现了工程化的重要性。
我的问题排查的能力在这次项目中得到了极大提升。从编译错误到链接失败,从 API 不匹配到命名空间问题,每一个问题的解决都让我学会了如何系统地分析和解决问题。特别是学会了从错误信息中快速定位问题根源的能力。
感受开源生态的温暖
在整个开发过程中,我深深感受到了开源社区的温暖。虽然我没有直接与项目维护者交流,但通过阅读代码注释、查看文档、分析错误信息,我感受到了无数开源贡献者的智慧和付出。
代码质量的标准让我震撼。tRPC-Cpp 的每一行代码都经过精心设计,注释详尽,接口清晰。这种对代码质量的追求,让我明白了什么是真正的专业精神。
文档的重要性也让我有了新的认识。从 README 到 API 文档,从示例代码到测试用例,每一个细节都体现了开源项目的用心。这让我明白了,好的代码不仅要能运行,更要能让别人理解和维护。
对未来的思考
这次经历让我对未来的职业发展有了更清晰的认识。持续学习的重要性在这次项目中体现地更直白了。从 C++ 基础到高级特性,从网络编程到并发编程,从版本控制到构建系统,每一个知识点都需要不断学习和实践。
开源贡献的价值。对一个心怀理想的开发者来说,不仅仅是技术能力的提升,更重要的是参与到一个更大的生态系统中,为开源世界贡献自己的力量。这种成就感是任何课堂学习都无法替代的。
深深的感激
特别感谢腾讯开源团队,感谢他们提供了这样宝贵的学习机会。通过参与真实的开源项目,我不仅提升了技术能力,更重要的是培养了工程思维和开源精神。
感谢 tRPC-Cpp 项目的所有贡献者,感谢他们构建了这样一个优秀的框架。通过阅读他们的代码,我学到了太多书本上学不到的知识。
感谢整个开源开发者生态,感谢所有为开源事业默默付出的开发者们。正是有了你们的贡献,才有了今天繁荣的开源世界,才有了我们这些后来者学习和成长的机会。