thrift.md 5.92 KB
Newer Older
wangxuefeng's avatar
wangxuefeng committed
1 2
[English Version](../en/thrift.md)

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

Ge Jun's avatar
Ge Jun committed
5
示例程序:[example/thrift_extension_c++](https://github.com/brpc/brpc/tree/master/example/thrift_extension_c++/)
wangxuefeng's avatar
wangxuefeng committed
6

Ge Jun's avatar
Ge Jun committed
7
相比使用原生方案的优势有:
wangxuefeng's avatar
wangxuefeng committed
8 9 10
- 线程安全。用户不需要为每个线程建立独立的client.
- 支持同步、异步、批量同步、批量异步等访问方式,能使用ParallelChannel等组合访问方式.
- 支持多种连接方式(连接池, 短连接), 支持超时、backup request、取消、tracing、内置服务等一系列RPC基本福利.
11
- 性能更好.
wangxuefeng's avatar
wangxuefeng committed
12

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

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

18
Linux下安装thrift依赖
Ge Jun's avatar
Ge Jun committed
19
先参考[官方wiki](https://thrift.apache.org/docs/install/debian)安装好必备的依赖和工具,然后从[官网](https://thrift.apache.org/download)下载thrift源代码,解压编译。
wangxuefeng's avatar
wangxuefeng committed
20 21 22 23 24
```bash
wget http://www.us.apache.org/dist/thrift/0.11.0/thrift-0.11.0.tar.gz
tar -xf thrift-0.11.0.tar.gz
cd thrift-0.11.0/
./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
Ge Jun's avatar
Ge Jun committed
25
make CPPFLAGS=-DFORCE_BOOST_SMART_PTR -j 4 -s
wangxuefeng's avatar
wangxuefeng committed
26 27
sudo make install
```
wangxuefeng's avatar
wangxuefeng committed
28

Ge Jun's avatar
Ge Jun committed
29
配置brpc支持thrift协议后make。编译完成后会生成libbrpc.a, 其中包含了支持thrift协议的扩展代码, 像正常使用brpc的代码一样链接即可。
wangxuefeng's avatar
wangxuefeng committed
30
```bash
31
# Ubuntu
Ge Jun's avatar
Ge Jun committed
32
sh config_brpc.sh --headers=/usr/include --libs=/usr/lib --with-thrift
33 34 35
# Fedora/CentOS
sh config_brpc.sh --headers=/usr/include --libs=/usr/lib64 --with-thrift
# Or use cmake
36
mkdir build && cd build && cmake ../ -DWITH_THRIFT=1
wangxuefeng's avatar
wangxuefeng committed
37
```
gejun's avatar
gejun committed
38
更多编译选项请阅读[Getting Started](../cn/getting_started.md)
wangxuefeng's avatar
wangxuefeng committed
39

Ge Jun's avatar
Ge Jun committed
40 41 42
# Client端访问thrift server
基本步骤:
- 创建一个协议设置为brpc::PROTOCOL_THRIFT的Channel
43 44
- 创建brpc::ThriftStub
- 使用原生Request和原生Response>发起访问
wangxuefeng's avatar
wangxuefeng committed
45

Ge Jun's avatar
Ge Jun committed
46
示例代码如下:
wangxuefeng's avatar
wangxuefeng committed
47 48
```c++
#include <brpc/channel.h>
49
#include <brpc/thrift_message.h>         // 定义了ThriftStub
wangxuefeng's avatar
wangxuefeng committed
50 51 52 53 54 55 56 57 58 59 60 61 62
...

DEFINE_string(server, "0.0.0.0:8019", "IP Address of thrift server");
DEFINE_string(load_balancer, "", "The algorithm for load balancing");
...
  
brpc::ChannelOptions options;
options.protocol = brpc::PROTOCOL_THRIFT;
brpc::Channel thrift_channel;
if (thrift_channel.Init(Flags_server.c_str(), FLAGS_load_balancer.c_str(), &options) != 0) {
   LOG(ERROR) << "Fail to initialize thrift channel";
   return -1;
}
Ge Jun's avatar
Ge Jun committed
63

64
brpc::ThriftStub stub(&thrift_channel);
wangxuefeng's avatar
wangxuefeng committed
65 66
...

Ge Jun's avatar
Ge Jun committed
67
// example::[EchoRequest/EchoResponse]是thrift生成的消息
68 69 70
example::EchoRequest req;
example::EchoResponse res;
req.data = "hello";
wangxuefeng's avatar
wangxuefeng committed
71

72
stub.CallMethod("Echo", &cntl, &req, &res, NULL);
wangxuefeng's avatar
wangxuefeng committed
73

Ge Jun's avatar
Ge Jun committed
74 75 76 77
if (cntl.Failed()) {
    LOG(ERROR) << "Fail to send thrift request, " << cntl.ErrorText();
    return -1;
} 
wangxuefeng's avatar
wangxuefeng committed
78 79
```

Ge Jun's avatar
Ge Jun committed
80 81
# Server端处理thrift请求
用户通过继承brpc::ThriftService实现处理逻辑,既可以调用thrift生成的handler以直接复用原有的函数入口,也可以像protobuf服务那样直接读取request和设置response。
wangxuefeng's avatar
wangxuefeng committed
82
```c++
83
class EchoServiceImpl : public brpc::ThriftService {
wangxuefeng's avatar
wangxuefeng committed
84
public:
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
    void ProcessThriftFramedRequest(brpc::Controller* cntl,
                                    brpc::ThriftFramedMessage* req,
                                    brpc::ThriftFramedMessage* res,
                                    google::protobuf::Closure* done) override {
        // Dispatch calls to different methods
        if (cntl->thrift_method_name() == "Echo") {
            return Echo(cntl, req->Cast<example::EchoRequest>(),
                        res->Cast<example::EchoResponse>(), done);
        } else {
            cntl->SetFailed(brpc::ENOMETHOD, "Fail to find method=%s",
                            cntl->thrift_method_name().c_str());
            done->Run();
        }
    }

    void Echo(brpc::Controller* cntl,
              const example::EchoRequest* req,
              example::EchoResponse* res,
              google::protobuf::Closure* done) {
wangxuefeng's avatar
wangxuefeng committed
104 105 106 107
        // This object helps you to call done->Run() in RAII style. If you need
        // to process the request asynchronously, pass done_guard.release().
        brpc::ClosureGuard done_guard(done);

108
        res->data = req->data + " (processed)";
wangxuefeng's avatar
wangxuefeng committed
109 110 111 112
    }
};
```

Ge Jun's avatar
Ge Jun committed
113
实现好thrift service后,设置到ServerOptions.thrift_service并启动服务
wangxuefeng's avatar
wangxuefeng committed
114
```c++
Ge Jun's avatar
Ge Jun committed
115
    brpc::Server server;
wangxuefeng's avatar
wangxuefeng committed
116
    brpc::ServerOptions options;
117
    options.thrift_service = new EchoServiceImpl;
wangxuefeng's avatar
wangxuefeng committed
118 119 120 121 122 123 124 125
    options.idle_timeout_sec = FLAGS_idle_timeout_s;
    options.max_concurrency = FLAGS_max_concurrency;

    // Start the server.
    if (server.Start(FLAGS_port, &options) != 0) {
        LOG(ERROR) << "Fail to start EchoServer";
        return -1;
    }
Ge Jun's avatar
Ge Jun committed
126
```
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145

# 简单的和原生thrift性能对比实验
测试环境: 48核  2.30GHz
## server端返回client发送的"hello"字符串
框架 | 线程数 | QPS | 平响 | cpu利用率
---- | --- | --- | --- | ---
native thrift | 60 | 6.9w | 0.9ms | 2.8%
brpc thrift | 60 | 30w | 0.2ms | 18%

## server端返回"hello" * 1000 字符串
框架 | 线程数 | QPS | 平响 | cpu利用率
---- | --- | --- | --- | ---
native thrift | 60 | 5.2w | 1.1ms | 4.5%
brpc thrift | 60 | 19.5w | 0.3ms | 22%

## server端做比较复杂的数学计算并返回"hello" * 1000 字符串
框架 | 线程数 | QPS | 平响 | cpu利用率
---- | --- | --- | --- | ---
native thrift | 60 | 1.7w | 3.5ms | 76%
146
brpc thrift | 60 | 2.1w | 2.9ms | 93%