Thrift架构简介

发展历程

Thrift最初由facebook开发用做系统内各语言之间的RPC通信。
2007年由facebook贡献到apache基金 ,085月进入apache孵化器。
目前支持的语言有C++, Java, Python, PHP, Ruby,Erlang, Perl,Haskell, C#, Cocoa, JavaScript,Node.js, Smalltalk, andOcaml可以在不同语言之间实现C/S RPC调用。

特色

传输数据采用二进制格式,相对XMLJSON体积更小,对于高并发、大数据量和多语言的环境更有优势。
Thrift允许你定义一个简单的定义文件中的数据类型和服务接口,以作为输入文件,编译器生成代码用来方便地生成RPC客户端和服务器通信的无缝跨编程语言。

例子_Python

首先介绍一个简单的 Thrift 实现实例,使大家能够快速直观地了解什么是 Thrift 以及如何使用 Thrift 构建服务。

创建一个简单的服务 Hello。首先根据 Thrift 的语法规范编写脚本文件 Hello.thrift,代码如下:

struct MessageMeta {
    1:i32 mid;
    2:string subject;
    3:i32 lablel0;
    4:string from_where;
    5:string to_where;
    6:i64 modifiedDate;
    7:i64 receivedDate;
    8:i64 sentDate;
}


service Hello{
    string helloString(1:string para, 2:string para2)
    MessageMeta hellowMessage(1:MessageMeta message)
 }

其中定义了一个数据结构 MessageMeta,由八个属性,包括INT32、STRING,INT64等类型。

定义了一个服务Hello,包括两个方法,每个方法都定义了参数列表以及返回值类型,每个参数包括参数序号,参数类型以及参数名。

之后在linux下执行 thrift -gen py Hello.thrift。

可以看到在当前目录下生成了一个新的文件夹gen-py,生成的代码在 gen-py/Hello/里面。包括Hello.py、constants.py、ttypes.py。
我们定义的MessageMeta在ttypes.py中生成了一个Class MessageMeta与之对应。
Hello服务则对应 Hello.py

框架

x
在最上层是用户自行实现的业务逻辑代码。    
第二层是由thrift编译器自动生成的代码,主要用于结构化数据的解析,发送和接收。TServer主要任务是高效的接受客户端请求,并将请求转发给Processor处理。Processor负责对客户端的请求做出响应,包括RPC请求转发,调用参数解析和用户逻辑调用,返回值写回等处理。上面例子里面Hello.py 就对应这个部分。
TProtocol以下部分是thirft的传输协议和底层I/O通信。TProtocol是用于数据类型解析的,将结构化数据转化为字节流给TTransport进行传输。TTransport是与底层数据传输密切相关的传输层,负责以字节流方式接收和发送消息体,不关注是什么数据类型。底层IO负责实际的数据传输,包括socket、文件和压缩数据流等。

数据类型

在Hello.thrift 我们看看到i32、i64、string这些就是thrift定义的数据类型,那么下面详细介绍一下thrift的数据类型。

基本数据类型

bool:布尔值,true 或 false,对应 Java 的 boolean
byte:8 位有符号整数,对应 Java 的 byte
i16:16 位有符号整数,对应 Java 的 short
i32:32 位有符号整数,对应 Java 的 int
i64:64 位有符号整数,对应 Java 的 long
double:64 位浮点数,对应 Java 的 double
string:未知编码文本或二进制字符串,对应Java 的 String

 
由于thrift是跨平台、跨语言的为了兼容所有只支持有符号整型。

结构体类型

例子中的MessageMeta就是一个结构体类型
struct:定义公共的对象,类似于C 语言中的结构体定义,在Java 中是一个JavaBean

成员是被正整数编号过的,其中的编号使不能重复的,这个是为了在传输过程中编码使用。

字段会有optionalrequired之分,但是如果不指定则为无类型可以不填充该值,但是在序列化传输的时候也会序列化进去,optional是不填充则部序列化,required是必须填充也必须序列化

同一文件可以定义多个struct,也可以定义在不同的文件,进行include引入。

每个字段可以设置默认值。


容器类型

l list <t>: 元素类型为 t 的有序表,容许元素重复。对应 c++ vector java ArrayList 或者其他语言的数组。
l set<t>: 元素类型为 t 的无序表,不容许元素重复。对应 c++ 中的 set java 中的 HashSet,python 中的 set php 中没有 set ,则转换为 list 类型
l map< t,t >: 键类型为 t ,值类型为 t kv 对,键不容许重复。对用 c++ 中的 map, Java HashMap , PHP 对应 array,Python/Ruby dictionary

异常类型

exception异常在语法和功能上类似于结构体,差别是异常使用关键字exception,而且异常是继承每种语言的基础异常类

服务类型

service:包括service_name 以及service里面包括的方法等。像例子中的service Hello

传输格式

TBinaryProtocol二进制格式
TCompactProtocol压缩格式
TJSONProtocol – JSON格式
TSimpleJSONProtocol提供JSON只写协议,生成的文件很容易通过脚本语言解析。
TDebugProtocol使用易懂的可读的文本格式,以便于debug
这些具体的数据处理方式可以看一下源码是怎么处理的,其中TCompactProtocol是压缩效率最高的。 我们来看一下对于int类型该协议是怎么处理的:


每8位中有1位tag和7位data组成。一个64位的数字最终有可能是10个字节,32位的则可能是5个字节,但是通常的时候数字并不是每个字节上都有数据,这个时候就使得这种压缩的效率提高了很多。

我们使用TBinaryProtocol在上面的例子基础上做一个简单RPC通信。
首先创建HelloServiceImp.py用来覆盖Hello.py里面Iface,写上自己的业务逻辑,代码如下:
# -*- coding: utf-8 -*-

from Hello import Iface

class HelloServiceImpl(
    Iface,
    ):

    def helloString(self, para, para2):
        print para, para2
        return para + para2

    def hellowMessage(self, message):
        return message
然后编辑HelloServiceServer.py 实现server的代码,代码如下:
# -*- coding: utf-8 -*-

from thrift.transport import TSocket
from thrift.protocol import TBinaryProtocol
from thrift.server import TProcessPoolServer

from Hello import Processor
from HelloServiceImpl import HelloServiceImpl

def service_server():
    transport = TSocket.TServerSocket(port=9090)
    factory = TBinaryProtocol.TBinaryProtocolFactory()
    processor = Processor(HelloServiceImpl())
    server = TProcessPoolServer.TProcessPoolServer(processor, transport)

    print('Start server on port 9090')
    server.serve()

service_server()

python HelloServiceServer.py 就能启动服务。
最后实现客户端代码:
# -*- coding: utf-8 -*-

from thrift.transport import TSocket
from thrift.protocol import TBinaryProtocol

from Hello import Client

def service_client():
    transport = TSocket.TSocket('localhost', 9090)
    transport.open()
    protocol = TBinaryProtocol.TBinaryProtocol(transport)
    client = Client(protocol)
    client.helloString('Hello', 'Thrift')
    transport.close()

service_client()
python  HelloServiceServer.py 就实现了一次c/s调用
如果需要使用其它的协议,只需要把服务器和客户端代码里面的 protocol 替换为相应的协议就可以。

传输方式

TSocket -阻塞式socker
THttpTransport采用Http传输协议进行数据传输
TFramedTransportframe为单位进行传输,非阻塞式服务中使用。
TFileTransport以文件形式进行传输。
TMemoryTransport将内存用于I/O. java实现时内部实际使用了简单的ByteArrayOutputStream
TZlibTransport使用zlib进行压缩,与其他传输方式联合使用。当前无java实现。

服务方式

TSimpleServer简单的单线程服务模型,常用于测试
TThreadPoolServer多线程服务模型,使用标准的阻塞式IO
TNonblockingServer多线程服务模型,使用非阻塞式IO(需使用TFramedTransport数据传输方式
等等


未来发展

Thrift经过这些年的发展,版本迭代,已经能够满足大部分需求,但是好像国内使用的不太多。
2015年Facebook推出了fbthrift, 作为Thrift的一个分支 ,包括新的 C++ 服务器。
Google这两年推出了基于ProtoBuf的gRPC,和Thrift有很多类似的地方,正在不断完善,估计未来会成为一个主流的rpc框架。









  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值