内容简介:thrift 初探
读研以来,很少关注高层架构的变动,所以忽略了期间服务化趋势带来的一些变化。近期,在某厂的面试中就被问到了服务调度和容错。
目前,稍大的企业基本都已进入或度过了服务治理的阶段,对于单节点的性能挖掘变得不再是那么迫切,服务调度、容错等问题才是焦点。之前通过开发服务器,基本掌握了 Linux 用户态的程序开发,对于服务化方面的知识和经验,相当欠缺。
预期和现实之间的差距,才是症结所在。受限于本人目前所拥有的硬件资源,只能从最基本的RPC开始。
0x00 前言
thrift是目前用得比较多的一款RPC框架,第一次听说thrift应该是大二时,只不过那时并没有需求,也就没有深入。
个人认为,一款 RPC(Remote Procedure Call) 框架至少应具备如下特征:
- 低层通信实现对调用者透明
- 支持不同的序列化表示,例如Json或二进制协议
- 支持不同的程序语言
显然thrift完全做到了上述几点,除此之外,它也做到了:
- 可替换的通信方式
- 可替换的序列化协议
- 多种服务模型,单线程、多线程、线程池等
得益于分层架构,对thrift进行扩展,难度并不大,虽然如此,我个人认为在内网,应该还是二进制协议+TCP为主,如果需要穿透防火墙,或许使用JSON+HTTP会更加合适。
0x01 编译安装
ubuntu 16.04的repository中有thrift-compiler这个包,但似乎并没有libthrift,所以为了使用最新的thrift,索性编译一个吧。
我在实验室台式机上的环境是ubuntu 16.04 server版,基本可以算是minimal安装,所以遇到一些依赖问题是在所难免的。有些问题,desktop版或许就不会遇到,因此各位请自行判断,话说 thrift官方文档 还真是简陋。
一些依赖:
- pkg-config:若不安装,会在configure时出现一个奇怪的错误,关键字QT-CORE
- libevent:不安装就无法开启非阻塞Server的支持
- boost:thrift几乎是重度依赖boost库
- libssl-dev:Transport层中有用到openssl
- flex和bison:用于生成IDL的解析前端
- 其它:libtool、automake、autoconf等,看错误安装即可
首先,生成configure:
./bootstrap
默认情况下,thrift会编译所有语言的库,如果你不需要该语言,在configure时需要加入:
--with-LANG=no 或 --without-LANG
你也可以通过如下命令查看选项:
./configure --help
接下来,make和make install。看得出来,官方文档基本是懒得写这些了,但作为初学者,这些还是挺重要的。要是连编译都搞不定,还怎么学整个框架?
0x02 thrift的架构
thrift采用的是严格的分层架构:
+-------------------------------------------+ | Server | | (single-threaded, event-driven etc) | +-------------------------------------------+ | Processor | | (compiler generated) | +-------------------------------------------+ | Protocol | | (JSON, compact etc) | +-------------------------------------------+ | Transport | | (raw TCP, HTTP etc) | +-------------------------------------------+
1. Transport层
用于实现具体的IO操作,但就通讯方式而言,你就可以选择如下类:
- Socket :TSocket
- Pipe :TPipe
- File :TFileTransport
- SSL :TSSLSocket
- Http :THttpTransport
还有一些没有提到的类,比如TBufferTransports,它就为基础的Transport提供Buffer,例如TSocket。
关于TTransport,是需要手动open和close的,别忘了。
2. Protocol层
涉及具体的序列化协议,在构造TProtocol的具体类时,需要传入TTransport类的实例。和Transport层一样,支持多种类型:
- Binary :TBinaryProtocol
- JSON :TJSONProtocol
- Compact :TCompactProtocol
这一层的继承体系比Transport层清晰很多,不会出现一层套一层的情况。
3. Processor层
由compiler生成的,使用者需要自行实现具体的逻辑,除了具体的Handler之外,还有对应的工厂类,可以有选择地实现。
4. Server层
支持不同的服务模型:
- 单线程 :TSimpleServer
- 多线程 :TThreadedServer
- 线程池 :TThreadPoolServer
- 非阻塞 :TNonblockingServer
构造Server的时候,你需要传入如下内容:
- 生成的Processor,或Processor工厂类
- 具体的TTransport,例如TServerSocket
- TTransport的工厂类
- TProtocol的工厂类
0x03 Client和Server的实现
就拿tutorial中的例子来说,需要做3件事:
- compiler根据service生成了具体的接口,位于gen-cpp/Calculator,需要在client中实现CalculateIf
- 如果需要,也可实现CalculatorIfFactory
- 实现client
- 实现server
1. 实现Client
boost::shared_ptr<TTransport> socket(new TSocket("localhost", 9090)); boost::shared_ptr<TTransport> transport(new TBufferedTransport(socket)); boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport)); CalculatorClient client(protocol); try { transport->open(); client.ping(); // ... transport->close(); } catch(TException& ex) { // ... }
很简洁,但是不要忘了open和close,其次异常的catch也不能忽视,尽管不太习惯在C++中使用异常。
2. 实现Server
这里以多线程模型为例:
TThreadedServer server( boost::make_shared<CalculatorProcessorFactory>(boost::make_shared<CalculatorCloneFactory>()), boost::make_shared<TServerSocket>(9090), boost::make_shared<TBufferedTransportFactory>(), boost::make_shared<TBinaryProtocolFactory>() ); server.serve();
从示例中看,还是挺简洁的,但是这里有不同的服务模型,所以需要完全掌握,还是要稍微花一点时间的。
0xFF 总结
经过端午假期的学习,可以说大概明白了thrift是怎么实现的,给他人所留的造轮子的空间确实不大。
当然也不是说没有小缺陷:
- 目前thrift对于boost库的依赖还是较重的,很多特性在C++11中已经实现
- 官方的文档太简陋,无论是细节还是具体的API,完全就是 程序员 随手撸的
官方提供的 whitepaper ,阅读体验倒是好得多,毕竟是两栏的,只不过内容似乎有点旧。
上述毕竟只是“初探”,很多内容没有涉及,诸如IDL,内部实现等,等之后大概读完thrift的lib后另起一篇。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。