Apache/brpc中的备份请求机制详解
什么是备份请求
在高并发分布式系统中,服务可用性至关重要。备份请求(Backup Request)是一种提高系统可用性和降低延迟的技术手段,其核心思想是:当主请求未在预期时间内返回时,立即向另一个服务实例发送相同的备份请求,最终取最先返回的结果。
Apache/brpc作为一款优秀的RPC框架,提供了完善的备份请求实现机制,能够帮助开发者轻松构建高可用的分布式系统。
brpc备份请求的实现方式
brpc提供了两种典型的备份请求实现方案,适用于不同的业务场景:
1. 单通道备份请求(推荐)
适用场景:当所有后端服务器都注册在同一个命名服务中时。
实现原理:
- 创建Channel时设置
ChannelOptions.backup_request_ms
参数 - brpc会先向一个服务器发送请求
- 如果超过
backup_request_ms
毫秒仍未收到响应,则自动向另一个服务器发送相同请求 - 取最先返回的结果作为最终响应
优势:
- 在合理设置
backup_request_ms
的情况下,大多数请求只会发送一次 - 对后端服务的额外压力极小
- 实现简单,只需设置一个参数
示例代码:
brpc::ChannelOptions options;
options.backup_request_ms = 2; // 设置2毫秒后触发备份请求
brpc::Channel channel;
if (channel.Init("server_address", &options) != 0) {
// 处理初始化失败
}
2. SelectiveChannel备份请求(集群间备份)
适用场景:当需要跨不同集群进行备份请求时。
实现原理:
- 创建一个SelectiveChannel
- 在SelectiveChannel中添加两个子Channel,每个子Channel对应一个集群
- 设置
backup_request_ms
参数 - 工作流程与单通道备份请求类似,但备份发生在不同集群间
优势:
- 可以实现跨集群的容灾备份
- 配置灵活,可以组合不同的负载均衡策略
如何合理设置backup_request_ms
backup_request_ms
参数的设置直接影响备份请求的效果,设置不当可能导致:
- 设置过小:过早触发备份请求,增加后端压力
- 设置过大:失去备份请求的意义,延迟无法降低
科学设置方法:
-
查看延迟分布:利用brpc提供的CDF(累积分布函数)图分析服务延迟分布
- Y轴表示延迟(默认微秒)
- X轴表示延迟小于Y轴值的请求比例
-
经验值参考:
- 覆盖95%请求:通常设置为P95延迟
- 覆盖99.9%请求:设置为P99.9延迟
-
自定义监控:可以通过以下代码添加自定义延迟统计:
#include <bvar/bvar.h>
#include <butil/time.h>
bvar::LatencyRecorder my_func_latency("my_func");
butil::Timer tm;
tm.start();
my_func();
tm.stop();
my_func_latency << tm.u_elapsed(); // 记录微秒级延迟
不推荐的实现方式
有些开发者可能会采用"双异步调用+取消"的方式实现备份请求:
// 不推荐的做法
void call_method() {
auto cntl1 = new brpc::Controller;
auto cntl2 = new brpc::Controller;
// 发起两个异步调用
stub1->method(cntl1, request1, response1, done1);
stub2->method(cntl2, request2, response2, done2);
// 在done回调中取消另一个请求
}
缺点:
- 每次调用都会发送两个请求,双倍后端压力
- 实现复杂,需要手动处理取消逻辑
- 资源浪费严重,不经济
最佳实践建议
- 优先使用单通道备份请求:在大多数场景下都是最佳选择
- 合理设置超时时间:基于实际延迟分布设置
backup_request_ms
- 监控调整:持续监控备份请求触发比例,适时调整参数
- 避免过度使用:对于已经很高的服务,备份请求可能适得其反
- 结合重试机制:可以与brpc的重试机制配合使用,但要注意避免雪崩
通过合理使用brpc的备份请求机制,可以显著提高系统的可用性和响应速度,同时将额外开销控制在合理范围内。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考