Q1ngbo commented on PR #3197:
URL: https://github.com/apache/brpc/pull/3197#issuecomment-3754426995
### 补充内容
#### fb协议处理的简要说明
Client应用会创建Stub,然后调用fbs中指定的method方法,之后会去调用channel->FBCallMethod。这些方法都是由flatbuffers自动生成的,而FBCallMethod是在brpc中定义的,此处是二者间的一个桥梁。由于FBCallMethod的实现与针对pb协议的CallMethod非常类似,所以我使用函数模板CallMethodInternal提取了二者中的公共部分,使用参数is_pb区分,CallMethod传入参数为true,FBCallMethod为false。发送路径上的序列化(SerializeFlatBuffersRequest)、Pack(PackFlatBuffersRequest)等操作已经被定义在了Protocol
fb_protocol中。
序列化函数SerializeFlatBuffersRequest的执行逻辑非常简单,首先根据FBRpcRequestHeader大小来调整message前面预留的header
buffer空间,然后零拷贝地将message中的SingleIOBuf
append至目的IOBuf就结束了。值得注意的是,fb协议中header的各字段被硬编码了,不能像pb一样通过proto文件(baidu_rpc_meta.proto)调整。
函数PackFlatBuffersRequest的功能与baidu_std协议中的PackRpcRequest函数类似,只不过rpc
header部分已经预先分配好。
Server应创建一个类,继承fb.h中生成的Service,并重载其virtual方法。在启动Server进程时,应将该类对象通过AddService将该service注册至brpc。接收到的请求会交由ProcessFlatBuffersRequest处理,它首先从msg->meta中提取出Header(这一步由SingleIOBuf::assign完成,可能会有拷贝);然后配置Controller,从msg->payload中解析出fb
message(同样会调用SingleIOBuf::assign);交由应用响应。应用逻辑处理完成后,会通过SendFlatBuffersRpcResponse向Client发送response
message,这里同样会将rpc header + message零拷贝地append到待发送IOBuf中。
#### 性能测试
我基于multi_threaded_echo_c++改造了benchmark程序,分别基于pb和fb协议实现,benchmark_fb的实现在#3196中。该程序基于bthread模型,共享同一个channel;每次发送时创建message,该message包含32B固定字段+
string组成的浮动字段(由request_size指定),proto文件定义如下;采用同步发送;输出指标包括延迟和QPS。
```c++
syntax="proto2";
option cc_generic_services = true;
package test;
message BenchmarkRequest {
required int32 opcode = 1;
required int32 echo_attachment = 2;
required int64 attachment_size = 3;
required int64 request_id = 4;
optional int64 reserved = 5;
optional string message = 4;
};
message BenchmarkResponse {
required int32 opcode = 1;
required int32 echo_attachment = 2;
required int64 attachment_size = 3;
required int64 request_id = 4;
optional int64 reserved = 5;
optional string message = 4;
};
service BenchmarkService {
rpc Test(BenchmarkRequest) returns (BenchmarkResponse);
};
```
测试目的是为了说明fb的处理效率优于pb。为了避免网络影响,测试在同机上进行,分别为client和server绑定4个核。
下表所示数据为thread_num=1,即bthread数目为1时的结果。测试过程中使用Req
Size变化请求中的string长度来改变message总大小,由于message中包含32B的固定整数部分,所以message实际总大小为32B(固定部分)
+ Req
Size,attachment为0。测试程序执行20s,记录平均QPS,单位为千次/秒。表格中pb(old)为原CallMethod实现,pb(new)为当前pr中基于函数模板CallMethodInternal的实现。表中最后一行展示的是fb相对于pb(new)的提升百分比,从该结果可知fb相对于pb有20~30%的性能提升,且使用函数模板后对pb几乎没影响。
协议\Req Size | 0B | 32B | 64B | 128B | 256B | 512B | 1024B | 2048B | 4096B |
8192B
-- | -- | -- | -- | -- | -- | -- | -- | -- | -- | --
pb(old) | 45k | 46k | 45k | 45k | 45k | 45k | 42k | 41k | 39k | 33k
pb(new) | 46k | 46k | 47k | 46k | 45k | 44k | 43k | 41k | 39k | 34k
fb | 58k | 58k | 58k | 58k | 57k | 57k | 55k | 52k | 48k | 43k
fb相对pb提升百分比 | 26.1% | 26.1% | 23.4% | 26.1% | 26.7% | 29.5% | 27.9% | 26.8%
| 23.1% | 26.5%
下表所示为thread_num=64,即并发bthread数目为64的测试结果,可以看到即使message大小为8KB,fb的提升仍有20.4%。
协议\Req Size | 0B | 32B | 64B | 128B | 256B | 512B | 1024B | 2048B | 4096B |
8192B
-- | -- | -- | -- | -- | -- | -- | -- | -- | -- | --
pb(old) | 526k | 522k | 519k | 511k | 492k | 471k | 441k | 397k | 348k | 282k
pb(new) | 531k | 521k | 519k | 515k | 490k | 470k | 440k | 399k | 340k | 279k
fb | 649k | 652k | 650k | 641k | 615k | 586k | 550k | 498k | 416k | 336k
fb相对pb提升百分比 | 22.2% | 27.3% | 25.2% | 24.5% | 25.5% | 24.7% | 25% | 24.8% |
22.4% | 20.4%
另外测试发现即使携带attachment,仍能保持相近的提升百分比,因为attachment不会被序列化。
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]