Access UB

brpc可通过多种方式访问用ub搭建的服务。

ubrpc (by protobuf)

r31687后,brpc支持通过protobuf访问ubrpc,不需要baidu-rpc-ub,也不依赖idl-compiler。(也可以让protobuf服务被ubrpc client访问,方法见使用ubrpc的服务)。

步骤:

  1. 用把idl文件转化为proto文件,老版本idl2proto不会转化idl中的service,需要手动转化。

    原先的echo.idl文件:

    1. string message;
    2. };
    3. struct EchoResponse {
    4. string message;
    5. };
    6. service EchoService {
    7. void Echo(EchoRequest req, out EchoResponse res);
    8. uint32_t EchoWithMultiArgs(EchoRequest req1, EchoRequest req2, out EchoResponse res1, out EchoResponse res2);
    9. };
  2. 插入如下片段以使用代码生成插件。

    BRPC_PATH代表brpc产出的路径(包含bin include等目录),PROTOBUF_INCLUDE_PATH代表protobuf的包含路径。注意–mcpack_out要和–cpp_out一致。

    1. protoc --plugin=protoc-gen-mcpack=$BRPC_PATH/bin/protoc-gen-mcpack --cpp_out=. --mcpack_out=. --proto_path=$BRPC_PATH/include --proto_path=PROTOBUF_INCLUDE_PATH
  3. 用channel发起访问。

    1. #include <brpc/channel.h>
    2. #include "echo.pb.h"
    3. ...
    4. brpc::Channel channel;
    5. brpc::ChannelOptions opt;
    6. opt.protocol = brpc::PROTOCOL_UBRPC_COMPACK; // or "ubrpc_compack";
    7. if (channel.Init(..., &opt) != 0) {
    8. LOG(ERROR) << "Fail to init channel";
    9. return -1;
    10. }
    11. EchoService_Stub stub(&channel);
    12. ...
    13. EchoRequest request;
    14. EchoResponse response;
    15. brpc::Controller cntl;
    16. request.set_message("hello world");
    17. stub.Echo(&cntl, &request, &response, NULL);
    18. if (cntl.Failed()) {
    19. LOG(ERROR) << "Fail to send request, " << cntl.ErrorText();
    20. return;
    21. }
    22. // 取response中的字段
    23. // [idl] void Echo(EchoRequest req, out EchoResponse res);
    24. // ^
    25. // response.message();

    多个请求要设置一下set_idl_names。

    例子详见example/echo_c++_ubrpc_compack

ubrpc (by baidu-rpc-ub)

server端由public/ubrpc搭建,request/response使用idl文件描述字段,序列化格式是compack或mcpack_v2。

步骤:

  1. 依赖public/baidu-rpc-ub模块,这个模块是brpc的扩展,不需要的用户不会依赖idl/mcpack/compack等模块。baidu-rpc-ub只包含扩展代码,brpc中的新特性会自动体现在这个模块中。

  2. 编写一个proto文件,其中定义了service,名字和idl中的相同,但请求类型必须是baidu.rpc.UBRequest,回复类型必须是baidu.rpc.UBResponse。这两个类型定义在brpc/ub.proto中,使用时得import。

    1. import "brpc/ub.proto"; // UBRequest, UBResponse
    2. option cc_generic_services = true;
    3. // Define UB service. request/response must be UBRequest/UBResponse
    4. service EchoService {
    5. rpc Echo(baidu.rpc.UBRequest) returns (baidu.rpc.UBResponse);
    6. };
  3. 在COMAKE包含baidu-rpc-ub/src路径。

    1. # brpc/ub.proto的包含路径
    2. PROTOC(ENV.WorkRoot()+"third-64/protobuf/bin/protoc")
    3. PROTOFLAGS("--proto_path=" + ENV.WorkRoot() + "public/baidu-rpc-ub/src/")
  4. 用法和访问其他协议类似:创建Channel,ChannelOptions.protocol为brpc::PROTOCOL_NSHEAD_CLIENT或**“nshead_client”**。request和response对象必须是baidu-rpc-ub提供的类型

    1. ...
    2. brpc::Channel channel;
    3. brpc::ChannelOptions opt;
    4. opt.protocol = brpc::PROTOCOL_NSHEAD_CLIENT; // or "nshead_client";
    5. if (channel.Init(..., &opt) != 0) {
    6. LOG(ERROR) << "Fail to init channel";
    7. return -1;
    8. EchoService_Stub stub(&channel);
    9. ...
    10. const int BUFSIZE = 1024 * 1024; // 1M
    11. char* buf_for_mempool = new char[BUFSIZE];
    12. bsl::xmempool pool;
    13. if (pool.create(buf_for_mempool, BUFSIZE) != 0) {
    14. LOG(FATAL) << "Fail to create bsl::xmempool";
    15. return -1;
    16. }
    17. // 构造UBRPC的request/response,idl结构体作为模块参数传入。为了构造idl结构,需要传入一个bsl::mempool
    18. brpc::UBRPCCompackRequest<example::EchoService_Echo_params> request(&pool);
    19. brpc::UBRPCCompackResponse<example::EchoService_Echo_response> response(&pool);
    20. // 设置字段
    21. request.mutable_req()->set_message("hello world");
    22. // 发起RPC
    23. brpc::Controller cntl;
    24. stub.Echo(&cntl, &request, &response, NULL);
    25. if (cntl.Failed()) {
    26. LOG(ERROR) << "Fail to Echo, " << cntl.ErrorText();
    27. return;
    28. }
    29. // 取回复中的字段
    30. response.result_params().res().message();
    31. ...

nshead+idl

server端是由public/ub搭建,通讯包组成为nshead+idl::compack/idl::mcpack(v2)

由于不需要指定service和method,无需编写proto文件,直接使用Channel.CallMethod方法发起RPC即可。请求包中的nshead可以填也可以不填,框架会补上正确的magic_num和body_len字段:

具体example代码可以参考,compack情况类似,不再赘述

nshead+mcpack(非idl产生的)

server端是由public/ub搭建,通讯包组成为nshead+mcpack包,但不是idl编译器生成的,RPC前需要先构造RawBuffer将其传入,然后获取mc_pack_t并按之前手工填写mcpack的方式操作:

  1. #include <brpc/ub_call.h>
  2. ...
  3. brpc::Channel channel;
  4. brpc::ChannelOptions opt;
  5. opt.protocol = brpc::PROTOCOL_NSHEAD_CLIENT; // or "nshead_client";
  6. if (channel.Init(..., &opt) != 0) {
  7. LOG(ERROR) << "Fail to init channel";
  8. return -1;
  9. }
  10. ...
  11. // 构造RawBuffer,一次RPC结束后RawBuffer可以复用,类似于bsl::mempool
  12. const int BUFSIZE = 10 * 1024 * 1024;
  13. brpc::RawBuffer req_buf(BUFSIZE);
  14. brpc::RawBuffer res_buf(BUFSIZE);
  15. // 传入RawBuffer来构造request和response
  16. brpc::UBRawMcpackRequest request(&req_buf);
  17. brpc::UBRawMcpackResponse response(&res_buf);
  18. // Fetch mc_pack_t and fill in variables
  19. mc_pack_t* req_pack = request.McpackHandle();
  20. int ret = mc_pack_put_str(req_pack, "mystr", "hello world");
  21. if (ret != 0) {
  22. LOG(FATAL) << "Failed to put string into mcpack: "
  23. break;
  24. }
  25. // Set fields of the request nshead struct if needed
  26. request.mutable_nshead()->version = 99;
  27. brpc::Controller cntl;
  28. channel.CallMethod(NULL, &cntl, &request, &response, NULL); // 假设channel已经通过之前所述方法Init成功
  29. // Get response from response buffer
  30. const mc_pack_t* res_pack = response.McpackHandle();
  31. mc_pack_get_str(res_pack, "mystr");

具体example代码可以参考。

nshead+blob

r32897后brpc直接支持用nshead+blob访问老server(而不用依赖baidu-rpc-ub)。example代码可以参考。

  1. #include <brpc/nshead_message.h>
  2. ...
  3. brpc::Channel;
  4. brpc::ChannelOptions opt;
  5. opt.protocol = brpc::PROTOCOL_NSHEAD; // or "nshead"
  6. if (channel.Init(..., &opt) != 0) {
  7. LOG(ERROR) << "Fail to init channel";
  8. return -1;
  9. }
  10. ...
  11. brpc::NsheadMessage request;
  12. brpc::NsheadMessage response;
  13. // Append message to `request'
  14. request.body.append("hello world");
  15. // Set fields of the request nshead struct if needed
  16. request.head.version = 99;
  17. brpc::Controller cntl;
  18. channel.CallMethod(NULL, &cntl, &request, &response, NULL);
  19. if (cntl.Failed()) {
  20. LOG(ERROR) << "Fail to access the server: " << cntl.ErrorText();
  21. return -1;
  22. }
  23. // response.head and response.body contains nshead_t and blob respectively.

或者用户也可以使用baidu-rpc-ub中的UBRawBufferRequest和UBRawBufferResponse来访问。example代码可以参考echo_c++_raw_buffer

  1. brpc::Channel channel;
  2. brpc::ChannelOptions opt;
  3. opt.protocol = brpc::PROTOCOL_NSHEAD_CLIENT; // or "nshead_client"
  4. if (channel.Init(..., &opt) != 0) {
  5. LOG(ERROR) << "Fail to init channel";
  6. return -1;
  7. }
  8. ...
  9. // 构造RawBuffer,一次RPC结束后RawBuffer可以复用,类似于bsl::mempool
  10. const int BUFSIZE = 10 * 1024 * 1024;
  11. brpc::RawBuffer req_buf(BUFSIZE);
  12. brpc::RawBuffer res_buf(BUFSIZE);
  13. // 传入RawBuffer来构造request和response
  14. brpc::UBRawBufferRequest request(&req_buf);
  15. brpc::UBRawBufferResponse response(&res_buf);
  16. // Append message to `request'
  17. request.append("hello world");
  18. // Set fields of the request nshead struct if needed
  19. request.mutable_nshead()->version = 99;
  20. brpc::Controller cntl;
  21. channel.CallMethod(NULL, &cntl, &request, &response, NULL); // 假设channel已经通过之前所述方法Init成功