搭建thrift服务

学习如何搭建thrift服务。

thrift是应用较广的RPC框架,最初由Facebook发布,后交由Apache维护。为了和thrift服务互通,同时解决thrift原生方案在多线程安全、易用性、并发能力等方面的一系列问题,brpc实现并支持thrift在NonBlocking模式下的协议(FramedProtocol), 下文均直接称为thrift协议。

示例程序:example/thrift_extension_c++

相比使用原生方案的优势有:

  • 线程安全。用户不需要为每个线程建立独立的client.
  • 支持同步、异步、批量同步、批量异步等访问方式,能使用ParallelChannel等组合访问方式.
  • 支持多种连接方式(连接池, 短连接), 支持超时、backup request、取消、tracing、内置服务等一系列RPC基本福利.
  • 性能更好.

编译

为了复用解析代码,brpc对thrift的支持仍需要依赖thrift库以及thrift生成的代码,thrift格式怎么写,代码怎么生成,怎么编译等问题请参考thrift官方文档。

brpc默认不启用thrift支持也不需要thrift依赖。但如果需用thrift协议, 配置brpc环境的时候需加上–with-thrift或-DWITH_THRIFT=ON.

Linux下安装thrift依赖 先参考官方wiki安装好必备的依赖和工具,然后从官网下载thrift源代码,解压编译。

  1. wget http://www.apache.org/dist/thrift/0.11.0/thrift-0.11.0.tar.gz
  2. tar -xf thrift-0.11.0.tar.gz
  3. cd thrift-0.11.0/
  4. ./configure --prefix=/usr --with-ruby=no --with-python=no --with-java=no --with-go=no --with-perl=no --with-php=no --with-csharp=no --with-erlang=no --with-lua=no --with-nodejs=no
  5. make CPPFLAGS=-DFORCE_BOOST_SMART_PTR -j 4 -s
  6. sudo make install

配置brpc支持thrift协议后make。编译完成后会生成libbrpc.a, 其中包含了支持thrift协议的扩展代码, 像正常使用brpc的代码一样链接即可。

  1. # Ubuntu
  2. sh config_brpc.sh --headers=/usr/include --libs=/usr/lib --with-thrift
  3. # Fedora/CentOS
  4. sh config_brpc.sh --headers=/usr/include --libs=/usr/lib64 --with-thrift
  5. # Or use cmake
  6. mkdir build && cd build && cmake ../ -DWITH_THRIFT=1

更多编译选项请阅读Getting Started

Client端访问thrift server

基本步骤:

  • 创建一个协议设置为brpc::PROTOCOL_THRIFT的Channel
  • 创建brpc::ThriftStub
  • 使用原生Request和原生Response>发起访问

示例代码如下:

  1. #include <brpc/channel.h>
  2. #include <brpc/thrift_message.h> // 定义了ThriftStub
  3. ...
  4. DEFINE_string(server, "0.0.0.0:8019", "IP Address of thrift server");
  5. DEFINE_string(load_balancer, "", "The algorithm for load balancing");
  6. ...
  7. brpc::ChannelOptions options;
  8. options.protocol = brpc::PROTOCOL_THRIFT;
  9. brpc::Channel thrift_channel;
  10. if (thrift_channel.Init(Flags_server.c_str(), FLAGS_load_balancer.c_str(), &options) != 0) {
  11. LOG(ERROR) << "Fail to initialize thrift channel";
  12. return -1;
  13. }
  14. brpc::ThriftStub stub(&thrift_channel);
  15. ...
  16. // example::[EchoRequest/EchoResponse]是thrift生成的消息
  17. example::EchoRequest req;
  18. example::EchoResponse res;
  19. req.data = "hello";
  20. stub.CallMethod("Echo", &cntl, &req, &res, NULL);
  21. if (cntl.Failed()) {
  22. LOG(ERROR) << "Fail to send thrift request, " << cntl.ErrorText();
  23. return -1;
  24. }

Server端处理thrift请求

用户通过继承brpc::ThriftService实现处理逻辑,既可以调用thrift生成的handler以直接复用原有的函数入口,也可以像protobuf服务那样直接读取request和设置response。

  1. class EchoServiceImpl : public brpc::ThriftService {
  2. public:
  3. void ProcessThriftFramedRequest(brpc::Controller* cntl,
  4. brpc::ThriftFramedMessage* req,
  5. brpc::ThriftFramedMessage* res,
  6. google::protobuf::Closure* done) override {
  7. // Dispatch calls to different methods
  8. if (cntl->thrift_method_name() == "Echo") {
  9. return Echo(cntl, req->Cast<example::EchoRequest>(),
  10. res->Cast<example::EchoResponse>(), done);
  11. } else {
  12. cntl->SetFailed(brpc::ENOMETHOD, "Fail to find method=%s",
  13. cntl->thrift_method_name().c_str());
  14. done->Run();
  15. }
  16. }
  17. void Echo(brpc::Controller* cntl,
  18. const example::EchoRequest* req,
  19. example::EchoResponse* res,
  20. google::protobuf::Closure* done) {
  21. // This object helps you to call done->Run() in RAII style. If you need
  22. // to process the request asynchronously, pass done_guard.release().
  23. brpc::ClosureGuard done_guard(done);
  24. res->data = req->data + " (processed)";
  25. }
  26. };

实现好thrift service后,设置到ServerOptions.thrift_service并启动服务

  1. brpc::Server server;
  2. brpc::ServerOptions options;
  3. options.thrift_service = new EchoServiceImpl;
  4. options.idle_timeout_sec = FLAGS_idle_timeout_s;
  5. options.max_concurrency = FLAGS_max_concurrency;
  6. // Start the server.
  7. if (server.Start(FLAGS_port, &options) != 0) {
  8. LOG(ERROR) << "Fail to start EchoServer";
  9. return -1;
  10. }

简单的和原生thrift性能对比实验

测试环境: 48核 2.30GHz

server端返回client发送的”hello”字符串

框架线程数QPS平响cpu利用率
native thrift606.9w0.9ms2.8%
brpc thrift6030w0.2ms18%

server端返回”hello” * 1000 字符串

框架线程数QPS平响cpu利用率
native thrift605.2w1.1ms4.5%
brpc thrift6019.5w0.3ms22%

server端做比较复杂的数学计算并返回”hello” * 1000 字符串

框架线程数QPS平响cpu利用率
native thrift601.7w3.5ms76%
brpc thrift602.1w2.9ms93%

修改于 2023年5月16日: add security bug fix pages (#148) (a29da9f)