thrift优缺点
优点
Thrift是一个跨语言的服务部署框架,最初由Facebook于2007年开发,2008年进入Apache开源项目。
Thrift通过一个中间语言(IDL, 接口定义语言)来定义RPC的接口和数据类型,然后通过一个编译器生成不同语言的代码(目前支持C++,Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk和OCaml),并由生成的代码负责RPC协议层和传输层的实现。
Thrift实际上是实现了C/S模式,通过代码生成工具将接口定义文件生成服务器端和客户端代码(可以为不同语言),从而实现服务端和客户端跨语言的支持。用户在Thirft描述文件中声明自己的服务,这些服务经过编译后会生成相应语言的代码文件,然后用户实现服务(客户端调用服务,服务器端提服务)便可以了。其中protocol(协议层, 定义数据传输格式,可以为二进制或者XML等)和transport(传输层,定义数据传输方式,可以为TCP/IP传输,内存共享或者文件共享等)被用作运行时库。
Thrift支持二进制,压缩格式,以及json格式数据的序列化和反序列化。这让用户可以更加灵活的选择协议的具体形式。更完美的是,协议是可自由扩展的,新版本的协议,完全兼容老的版本!
缺点
极其缺少文档,只能通过读thrift代码充分的使用thrift,洽洽这是一件有乐趣的事情。
性能
在CompactProtocol情况下性能和ProtoBuffer相当,
BinaryProtocol情况下性能是ProtoBuffer的60%左右。
thrift文件定义
namespace cpp example struct Book_Info { 1: i32 book_id, 2: string book_name, 3: string book_author, 4: double book_price, 5: string book_publisher, } namespace cpp example include "book.thrift" service BookServlet { bool Sender(1: list<book.Book_Info> books); oneway void Sender2(1: list<book.Book_Info> books); }
代码生成
book.thrift
/usr/bin/thrift --gen cpp book.thrift
thrift会在gen-cpp下面生成对应的cpp文件:
├── book_constants.cpp ├── book_constants.h ├── book_types.cpp └── book_types.h
rpc.thrift
/usr/bin/thrift --gen cpp rpc.thrift
thrift会在gen-cpp下面生成对应的cpp文件:
├── BookServlet.cpp ├── BookServlet.h ├── BookServlet_server.skeleton.cpp ├── rpc_constants.cpp ├── rpc_constants.h ├── rpc_types.cpp └── rpc_types.h
client端代码
#include "gen-cpp/BookServlet.h" #include <thrift/transport/TSocket.h> #include <thrift/transport/TBufferTransports.h> #include <thrift/protocol/TBinaryProtocol.h> using namespace apache::thrift; using namespace apache::thrift::transport; using namespace apache::thrift::protocol; using namespace example; int main(int argc, char** argv) { 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)); example::BookServletClient client(protocol); try { transport->open(); std::vector<Book_Info> books; books.push_back(Book_Info()); Book_Info &t0 = *books.rbegin(); t0.book_name = "bookname0"; books.push_back(Book_Info()); Book_Info &t1 = *books.rbegin(); t1.book_name = "bookname1"; client.Sender(books); transport->close(); } catch (TException &tx) { printf("ERROR: %s\n", tx.what()); } printf("the end\n"); return 0; }
server端代码
#include <thrift/protocol/TBinaryProtocol.h> #include <thrift/server/TSimpleServer.h> #include <thrift/transport/TServerSocket.h> #include <thrift/transport/TBufferTransports.h> #include <iostream> #include "gen-cpp/BookServlet.h" using namespace ::apache::thrift; using namespace ::apache::thrift::protocol; using namespace ::apache::thrift::transport; using namespace ::apache::thrift::server; using namespace example; class BookServletHandler : virtual public BookServletIf { public: BookServletHandler() {} bool Sender(const std::vector<Book_Info> & books) { typedef std::vector<Book_Info>::const_iterator Itr; for (Itr i = books.begin(); i != books.end(); ++i) { std::cout<<i->book_name<<std::endl; } } void Sender2(const std::vector<Book_Info> & books) { printf("Sender2\n"); } }; int main(int argc, char **argv) { boost::shared_ptr<BookServletHandler> handler(new BookServletHandler()); boost::shared_ptr<TProcessor> processor(new BookServletProcessor(handler)); boost::shared_ptr<TServerTransport> serverTransport(new TServerSocket(9090)); boost::shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory()); boost::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory()); TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory); server.serve(); return 0; }
编译和运行
g++ client.cpp gen-cpp/book_constants.cpp gen-cpp/BookServlet.cpp gen-cpp/book_types.cpp -lthrift -o client g++ server.cpp gen-cpp/book_constants.cpp gen-cpp/BookServlet.cpp gen-cpp/book_types.cpp -lthrift -o server