Thrift 笔记 Copyright@QingleiLi

Apache Thrift 采用接口描述语言定义并创建服务,支持可扩展的跨语言服务开发,所包含的代码生成引擎可以在多种语言中,如 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk 等创建高效的、无缝的服务,其传输数据采用二进制格式,相对 XML 和 JSON 体积更小,对于高并发、大数据量和多语言的环境更有优势。

安装

依赖

  • pip

安装

  1. 在Thrift官网下载源码,下载地址

  2. 解压源码,进行./configure,会生成make文件,并打印编译信息,在最后会有提示信息,笔者只有python环境,所以只检测到了python库

    thrift 0.9.3
    
    Building C++ Library ......... : no
    Building C (GLib) Library .... : no
    Building Java Library ........ : no
    Building C# Library .......... : no
    Building Python Library ...... : yes
    Building Ruby Library ........ : no
    Building Haxe Library ........ : no
    Building Haskell Library ..... : no
    Building Perl Library ........ : no
    Building PHP Library ......... : no
    Building Erlang Library ...... : no
    Building Go Library .......... : no
    Building D Library ........... : no
    Building NodeJS Library ...... : no
    Building Lua Library ......... : no
    
    Python Library:
       Using Python .............. : /usr/bin/python
       Using Trial ............... : /usr/bin/trial
    
    If something is missing that you think should be present,
    please skim the output of configure to find the missing
    component.  Details are present in config.log.
    
  3. 编译,检查源码make && make check,make check的时间会很长,大概进行了528项测试Test run #528,如果报错,根据具体情况分析

  4. 安装thrift主体,sudo make install

  5. 检验thrift是否安装成功

    $ thrift -version
    Thrift version 0.9.3
    
  6. 安装Python支持

    sudo pip install thrift
    
  7. 检验python支持是否安装成功

    $ python
    Python 2.7.3 (default, Jun 22 2015, 19:43:34) 
    [GCC 4.6.3] on linux2
    >>> import thrift
    

不报错就好了。

其他

  • 官网

    http://thrift.apache.org/
    
  • 概述

  1. 支持的传输格式,负责数据编码

    	TBinaryProtocol   二进制格式
    	TCompactProtocol  压缩格式,密集二进制编码
    	TJSONProtocol     JSON格式
    	TSimpleJSONProtocol 提供JSON只写协议,生成的文件很容易通过脚本语言解析
    	TDebugProtocol     使用易懂的可读的文本格式以便于debug
    	dir(thrift.protocol)
    		['TBase', 'TBinaryProtocol', 'TCompactProtocol', 'TJSONProtocol', 'TProtocol',  'fastbinary']
    
  2. 支持的数据传输方式,负责数据传输

    	TSocket    			采用TCP Socket进行数据传输,阻塞式socket
    	THttpTransport		采用HTTP传输协议进行数据传输
    	TFileTransport		文件(日志)传输类,以文件形式进行传输,允许client将文件传给server,允许server将收到的数据写到文件中
    	TZlibTransport		使用zlib进行压缩,压缩后对数据进行传输,或者将收到的数据解压
    	下面几个类主要是对上面几个类地装饰(采用了装饰模式),以提高传输效率。
    	TBufferedTransport	对某个transport对象操作的数据进行buffer,即从buffer中读取数据进行传输,或将数据直接写入到buffer
    	TFramedTransport	以frame为单位传输,非阻塞式服务中使用
    	TMemoryBuffer		将内存用于I/0,从一个缓冲区中读写数据
    	dir(thrift.transport)传输层
    		['THttpClient', 'TSocket', 'TTransport', 'TTwisted', 'TZlibTransport', ]
    	dir(thrift.transport.TTransport)
    		['CReadableTransport', 'StringIO', 'TBufferedTransport', 'TBufferedTransportFactory', 'TException', 
    		'TFileObjectTransport', 'TFramedTransport', 'TFramedTransportFactory', 'TMemoryBuffer', 
    		'TSaslClientTransport', 'TServerTransportBase', 'TTransportBase', 'TTransportException', 
    		'TTransportFactoryBase',]
    
  3. 支持的服务模型[主要是服务端类型]

    	TSimpleServer		简单的单线程服务模型,常用于测试
    	TThreadedServer		多线程服务模型使用标准的阻塞式IO,每个请求创建一个线程
    	TThreadPoolServer	多线程服务模型使用标准的阻塞式IO,预先创建一组线程处理请求
    	TNonblockingServer	多线程服务模型使用非阻塞IO,TFramedTransport必须使用该类型的server
    	dir(thrift.server)
    		['TNonblockingServer', 'TServer',]
    	dir(thrift.server.TServer)
    		['Queue', 'TBinaryProtocol', 'TForkingServer', 'TProcessor', 'TServer', 'TSimpleServer', 
    		'TThreadPoolServer', 'TThreadedServer', 'TTransport', 'logger', 'logging', 'os', 'sys', 'threading', 
    		'traceback']
    	dir(thrift.server.TNonblockingServer)
    	['CLOSED', 'Connection', 'Queue', 'SEND_ANSWER', 'TBinaryProtocolFactory', 'TNonblockingServer', 
    	'TTransport', 'WAIT_LEN', 'WAIT_MESSAGE', 'WAIT_PROCESS', 'Worker', 'logger', 'logging', 'select', 
    	'socket', 'socket_exception', 'struct', 'threading']
    
  • 编译器生成的文件列表

  • Python

    	constants.py: 包含声明的所有常量
    	ttypes.py: 包含声明的struct,实现了具体的序列化和反序列化
    	Hello.py :对应service的描述文件,包含了:
    		Iface: service接口定义
    		Client: client的rpc调用桩
    		Processor: 处理service的具体方法调用,需要传入server端实现的handler
    

使用

基本使用

  1. 书写thrift文件,该文件为接口的声明,是提供对外提供服务的接口,不在该文件中的函数是无法调用的

    #Hello.thrift
    service Hello{ 
    	string hello(1:string para)
    }
    

thrift文件由Thrift接口定义语言(IDL, Interface Definition Language)书写

  1. 使用thrift编译器编译thrift文件,生成gen-py文件夹(该文件夹生成在运行命令的路径下,而不是源码所在路径),文件夹内生成远程调用所需文件

    thrift --gen py Hello.thrift
    #生成java支持
    #thrift --gen java Hello.thrift
    
  2. 编写服务器端代码

    #!/usr/bin/env python
    
    # 将gen-py加入环境变量,因为名字里有-,无法直接import
    import sys
    sys.path.append('./gen-py')
    
    # 引入接口
    from Hello import Hello
    
    # 引入thrift的socket和协议
    import thrift
    from thrift.transport import TSocket
    from thrift.transport import TTransport
    from thrift.protocol import TBinaryProtocol
    from thrift.server import TServer
    
    # 实现接口
    class HelloHandler:
        def __init__(self):
        	pass
    
        def helloString(self,s):
            print "client:" + s
            return "server:" + s
    
    if __name__== "__main__":
    	# 实现接口的类实例
    	handler = HelloHandler()
    	# 将实例作为处理器传给接口
    	processor = Hello.Processor(handler)
    
    	# 创建服务socket
    	transport = TSocket.TServerSocket('localhost', 30303)
    	# 创建传输层协议(缓存socket)
    	tfactory = TTransport.TBufferedTransportFactory()
    	# 创建数据传输形式(二进制)
    	pfactory = TBinaryProtocol.TBinaryProtocolFactory()
    
    	# 创建服务对象
    	server = TServer.TSimpleServer(processor, transport, tfactory, pfactory)
    
    	print "Starting python server..."
    	# 运行服务
    	server.serve()
    	print "done!"
    
  3. 编写客户端代码

    #!/usr/bin/env python
    
    # 将gen-py加入环境变量,因为名字里有-,无法直接import
    import sys
    sys.path.append('./gen-py')
    
    # 引入接口
    from Hello import Hello
    
    # 引入thrift的socket和协议
    import thrift
    from thrift.transport import TSocket
    from thrift.transport import TTransport
    from thrift.protocol import TBinaryProtocol
    
    if __name__ == '__main__':
        try:
            # 创建socket
            transport = TSocket.TSocket('localhost', 30303)
    
            # 使用缓存传输层包装
            transport = TTransport.TBufferedTransport(transport)
    
            # 使用二进制传输方式包装
            protocol = TBinaryProtocol.TBinaryProtocol(transport)
    
            # 使用创建的协议生成一个客户端
            client = Hello.Client(protocol)
    
            # 打开传输层连接
            transport.open()
            # 调用远程函数
            print client.helloString("test")
            print "done"
            
            # 关闭传输层连接
            transport.close()
    
        except Thrift.TException, tx:
            print "%s" % (tx.message)
    
  4. 运行程序

    $ python server.py 
    Starting python server...
    client:test
    
    $ python client.py 
    server:test
    done
    

应用

错误汇总

解决办法:

注意

  • thrift不支持无符号整型,因为很多目标语言不存在无符号整型(如java)。

参考资料

概述:http://dongxicheng.org/search-engine/thrift-guide/
C++例子:http://dongxicheng.org/search-engine/thrift-rpc/
总结:http://blog.csdn.net/chosen0ne/article/details/22735973
总结,部分异步:http://blog.chinaunix.net/uid-20357359-id-2876170.html
IBM:http://www.ibm.com/developerworks/cn/java/j-lo-apachethrift/
http://blog.csdn.net/zlzlei/article/details/8500106
http://www.douban.com/group/topic/40717269/
thrift-missing-guide:http://diwakergupta.github.io/thrift-missing-guide/