备份请求
Backup request
学习如何使用备份请求。
有时为了保证可用性,我们需要同时访问两个服务,并取回最先返回的结果。在 brpc 中有几种方式可以做到这一点:
当后端服务器在命名服务中可被标记为挂起时
Channel 发起备份请求。Channel 将请求发送给其中一台服务器,若在 ChannelOptions.backup_request_ms 毫秒内没有收到响应,则把请求发送给另一台服务器,并采用最先返回的响应。合理设置 backup_request_ms 之后,大多数情况下只会发出一个请求,因此不会给后端服务带来额外压力。
参考 example/backup_request_c++](https://github.com/brpc/brpc/blob/master/example/backup_request_c++) 中的示例代码。在这个示例中,当请求数为偶数时,客户端会在 2ms 后发送备份请求,而服务端则故意睡眠 20ms,从而触发备份请求。
运行之后,客户端和服务端的日志如下。"Index" 是请求编号。服务端收到第一个请求后,会故意睡眠 20ms。随后客户端发送具有相同 index 的请求。最终的延迟不受这次故意睡眠的影响。


/rpcz 同样显示客户端在 2ms 后触发了备份请求,并发送了第二个请求。

选择合适的 backup_request_ms
你可以查看 brpc 提供的默认延迟 cdf(累积分布函数)图,也可以自行添加。cdf 图的 y 轴是延迟(默认单位为微秒),x 轴是延迟小于 y 轴对应值的请求所占的比例。在下图中,选择 backup_request_ms=2ms 大约可以覆盖 95.5% 的请求,而选择 backup_request_ms=10ms 则可以覆盖 99.99% 的请求。

自行添加的方式:
#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(); // u represents for microsecond, and s_elapsed(), m_elapsed(), n_elapsed() correspond to second, millisecond, nanosecond.
// All work is done here. My_func_qps, my_func_latency, my_func_latency_cdf and many other counters would be shown in /vars.当后端服务器无法在命名服务中挂起时
[推荐] 定义一个设置了 backup request 的 SelectiveChannel,其中包含两个子 channel。该 SelectiveChannel 的访问过程与上述情况类似:它会先访问其中一个子 channel,如果在 channelOptions.backup_request_ms 毫秒后仍未返回响应,再访问另一个子 channel。如果每个子 channel 对应一个集群,那么该方法就是在两个集群之间进行备份请求。SelectiveChannel 的示例可参见 example/selective_echo_c++,更多细节请参考上述程序。
[不推荐] 发起两次异步 RPC 调用并将它们合并,在各自的 done 回调中相互取消。示例见 example/cancel_c++。该方法的问题在于程序总是发送两个请求,使后端服务的压力翻倍。无论从哪个角度看这都是不划算的,应尽可能避免。
最后修改于 2022 年 1 月 30 日:bRPC website 1.0 (92b925e8f)
评论
登录后参与评论
KnowForge