Thrift基础

        Thrift源于大名鼎鼎的facebook之手,在2007年facebook提交Apache基金会将Thrift作为一个开源项目,对于当时的facebook来说创造thrift是为了解决facebook系统中各系统间大数据量的传 输通信以及系统之间语言环境不同需要跨平台的特性。所以thrift可以支持多种程序语言,例如:  C++, C#, Cocoa, Erlang, Haskell, Java, Ocami, Perl, PHP, Python, Ruby, Smalltalk. 在多种不同的语言之间通信thrift可以作为二进制的高性能的通讯中间件,支持数据(对象)序列化和多种类型的RPC服务。Thrift适用于程序对程 序静态的数据交换,需要先确定好他的数据结构,他是完全静态化的,当数据结构发生变化时,必须重新编辑IDL文件,代码生成,再编译载入的流程,跟其他IDL工具相比较可以视为是Thrift的弱项,Thrift适用于搭建大型数据交换及存储的通用工具,对于大型系统中的内部数据传输相对于JSON和xml无论在性能、传输大小上有明显的优势。

        Thrift 基础架构是一个服务端和客户端的架构体系,从我个人的感官上来看Thrift是一个类似XML-RPC+Java-to- IDL+Serialization Tools=Thrift 的东东,Thrift 具有自己内部定义的传输协议规范(TProtocol)和传输数据标准(TTransports),通过IDL脚本对传输数据的数据结构(struct) 和传输数据的业务逻辑(service)根据不同的运行环境快速的构建相应的代码,并且通过自己内部的序列化机制对传输的数据进行简化和压缩提高高并发、 大型系统中数据交互的成本,下图描绘了Thrift的整体架构,分为6个部分:1.你的业务逻辑实现(You Code) 2.客户端和服务端对应的Service 3.执行读写操作的计算结果4.TProtocol 5.TTransports  6.底层I/O通信
thrift

图 中前面3个部分是1.你通过Thrift脚本文件生成的代码,2.图中的褐色框部分是你根据生成代码构建的客户端和处理器的代码,3.图中红色的部分是2 端产生的计算结果。从TProtocol下面3个部分是Thrift的传输体系和传输协议以及底层I/O通信,Thrift并且提供 堵塞、非阻塞,单线程、多线程的模式运行在服务器上,还可以配合服务器/容器一起运行,可以和现有JEE服务器/Web容器无缝的结合。

Thrift与其他传输方式的比较
    xml与JSON相比体积太大,但是xml传统,也不算复杂。
    json 体积较小,新颖,但不够完善。
    thrift 体积超小,使用起来比较麻烦,不如前两者轻便,但是对于1.高并发、2.数据传输量大、3.多语言环境, 满足其中2点使用 thrift还是值得的。

  假定需要传输相同的内容,但使用不同的方式从 1、传输内容所产生的大小 2、传输过程中服务端和客户端所产生的开销,这2个方便进行比较。使用Thrift和其他方式的所产生的内容大小比较结果如下:

 thrift-size

 

 在上图中我们能明显看出,最臃肿的是RMI,其次是xml,使用Thrift的TCompactProtocol协议和Google 的 Protocol Buffers 相差的不算太多,相比而言还是Google 的 Protocol Buffers效果最佳。

使用Thrift 中的协议和其他方式的所产生的运行开销比较结果如下:
  thrift-load

   在上图中我们能明显看出,最占资源是REST2中协议,使用Thrift的TCompactProtocol协议和Google 的 Protocol Buffers 相差的不算太多,相比而言Thrift的TCompactProtocol协议效果最佳。哇,看了上面的比较,我突然想后面写一篇Google 的 Protocol Buffers的用法相关的文字

1)数据类型

  基本类型

    bool:布尔值,true 或 false,对应 C++ 的 bool

    byte:8 位有符号整数,对应 C++ 的 byte

    i16:16 位有符号整数,对应 C++ 的 short

    i32:32 位有符号整数,对应 C++ 的 int

    i64:64 位有符号整数,对应 C++ 的 long

    double:64 位浮点数,对应 C++ 的 double

    string:utf-8编码的字符串,对应 C++ 的 string

  结构体类型

    struct:定义公共的对象,类似于 C 语言中的结构体定义

  容器类型

    list:对应 C++ 的 list

    set:对应 C++ 的 set

    map:对应 C++ 的map

  异常类型

    exception:对应 C++ 的 Exception

  服务类型

    service:对应服务的类

  (2)通讯支持

   支持的数据传输协议(传输格式)

      TBinaryProtocol : 二进制格式.

      TCompactProtocol : 压缩格式

      TJSONProtocol : JSON格式

      TSimpleJSONProtocol : 提供JSON只写协议, 生成的文件很容易通过脚本语言解析

      tips: 客户端和服务端的协议要一致

  支持的数据传输方式

    TSocket -阻塞式socker

    TFramedTransport–以frame为单位进行传输,非阻塞式服务中使用。

    TFileTransport – 以文件形式进行传输。

    TMemoryTransport –将内存用于I/O. java实现时使用了简单的ByteArrayOutputStream。

    TZlibTransport – 使用zlib进行压缩, 与其他传输方式联合使用。当前无java实现。

   支持的服务模型

    TSimpleServer – 简单的单线程服务模型,常用于测试教学使用

    TThreadPoolServer – 多线程服务模型,使用标准的阻塞式IO。

    TNonblockingServer – 多线程服务模型,使用非阻塞式IO(需使用TFramedTransport数据传输方式)

3 一个例子

  (1)、编写idl文件

  编写calculate.idl如下:

namespace cpp calculate

service Calculator

{

i32 add(1:i32 add_num1, 2:i32 add_num2),

i32 subtract(1:i32 sub_num1, 2:i32 sub_num2)

}

 

 

 

  (2)、编译生成框架文件(C++)

 

  Thrift由两部分组成:编译器(在compiler目录下,采用C++编写)和服务器(在lib目录下),其中编译器的作用是将用户定义的thrift文件编译生成对应语言的代码,而服务器是事先已经实现好的、可供用户直接使用的RPC Server(当然,用户也很容易编写自己的server)。

  在idl文件所在路径打开cmd,输入:thrift-0.9.3.exe --gen cpp calculate.idl

  结果代码存放在gen-cpp目录下,其中的文件说明:

      calculate_constants:idl文件中一些常量的定义

      calculate_types:idl文件中定义的数据类型

      Calculator:idl文件中定义的服务

  Calculator_server.skeleton:给出一个Server端代码框架

  (3)、编写服务端Server

       将Calculator_server.skeleton.cpp内容拷贝,并在main函数开始部分添加代码:

  1  TWinsockSigleton::create(); //高版本不再需要
  2  int port = 9090;

 

  (4)、编写客户端Client

 

 1 #include "Calculator.h"
 2 #include <thrift/transport/TSocket.h>
 3 #include <thrift/transport/TBufferTransports.h>
 4 #include <thrift/protocol/TBinaryProtocol.h>
 5 #include <thrift/server/TSimpleServer.h>
 6 #include <thrift/transport/TServerSocket.h>
 7 #include <thrift/transport/TBufferTransports.h>
 8 
 9 using namespace apache::thrift;
10 using namespace apache::thrift::protocol;
11 using namespace apache::thrift::transport;
12 using boost::shared_ptr;
13 using namespace  ::calculate;
14 int main(int argc, char **argv)
15 {
16     shared_ptr<TSocket> socket(new TSocket("127.0.0.1",9090));
17     shared_ptr<TTransport> transport(new TBufferedTransport(socket));
18     shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
19     CalculatorClient client(protocol);
20     try
21     {
22         transport->open();
23     }
24     catch(TTransportException)
25     {
26         transport->close();
27     }
28 
29     int res_add = client.add(1, 2);
30     printf("client.add(%d, %d) = %d\n", 1, 2, res_add);
31     int res_subtract = client.subtract(3, 2);
32     printf("client.subtract(%d, %d) = %d\n", 3, 2, res_subtract);
33     transport->close();
34 
35     getchar();
36     return 0;
37 }

 

  注:无论是Client还是Server,都必须包含必要的头文件和链接所需要的静态库文件。

  包含目录:工程配置页,C/C++ -> General -> Additional  Include Directories

  库目录:工程配置页,Linker -> General -> Additional  Library Directories,并在Input -> Additional Dependencies加入lib

  除此之外,还需要OpenSSL的包含路径和库路径,安装后指定即可。

   通过上面的例子分析可以看出,Thrift最重要的组件是编译器(采用C++编写),它为用户生成了网络通信相关的代码,从而大大减少了用户的编码工作。

  Thrift采用了C/S模型,不支持双向通信:client只能远程调用server端的RPC接口,但client端则没有RPC供server端调用,这意味着,client端能够主动与server端通信,但server端不能主动与client端通信而只能被动地对client端的请求作出应答。这种RPC模式在某些应用中存在缺陷,比如:有些应用,在大部分情况下,client端会主动向server端发请求或者向server端发送数据,而在少部分情况下,server端也需要主动向client发送一些命令,告知进行某些操作。为了解决该问题,通常使用双client/server,通信双方都既是client,也是server。该方案需要在通信双方之间建立两个通信通道,开启两个端口,这比较繁琐,且很不优雅。但仍是目前普遍采用的一套方案。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值