Python Thrift示例

发布时间:2019-09-12 08:02:20编辑:auto阅读(31)

    前言

    Apache Thrift 是 Facebook 实现的一种高效的、支持多种编程语言的远程服务调用的框架。本文将从 Python开发人员角度简单介绍 Apache Thrift 的架构、开发和使用。

    Thrift简介

    Thrift network stack

    Transport

    Transport网络读写(socket,http等)抽象,用于和其他thrift组件解耦。
    Transport的接口包括:open, close, read, write, flush, isOpen, readAll。
    Server端需要ServerTransport(对监听socket的一种抽象),用于接收客户端连接,接口包括:listen, accept, close。
    python中Transport的实现包括:TSocket, THttpServer, TSSLSocket, TTwisted, TZlibTransport,都是对某种协议或框架的实现。还有两个装饰器,用于为已有的Transport添加功能,TBufferedTransport(增加缓冲)和TFramedTransport(添加帧)。
    在创建server时,传入的时Tranport的工厂,这些Factory包括:TTransportFactoryBase(没有任何修饰,直接返回),TBufferedTransportFactory(返回带缓冲的Transport)和TFramedTransportFactory(返回帧定位的Transport)。
    

    Protocol

    Protocol用于对数据格式抽象,在rpc调用时序列化请求和响应。
    TProtocol的实现包括:TJSONProtocol,TSimpleJSONProtocol,TBinaryProtocol,TBinaryPotocolAccelerated,TCompactProtocol。
    

    Processor

    Processor对stream读写抽象,最终会调用用户编写的handler已响应对应的service。具体的Processor有compiler生成,用户需要实现service的实现类。
    

    Server

    Server创建Transport,输入、输出的Protocol,以及响应service的handler,监听到client的请求然后委托给processor处理。
    TServer是基类,构造函数的参数包括:
    1) processor, serverTransport
    2) processor, serverTransport, transportFactory, protocolFactory
    3) processor, serverTransport, inputTransportFactory, outputTransportFactory, inputProtocolFactory, outputProtocolFactory   
    TServer内部实际上需要3)所列的参数,1)和2)会导致对应的参数使用默认值。
    TServer的子类包括:TSimpleServer, TThreadedServer, TThreadPoolServer, TForkingServer, THttpServer, TNonblockingServer, TProcessPoolServer
    TServer的serve方法用于开始服务,接收client的请求。
    

    Code generated

    constants.py: 包含声明的所有常量
    ttypes.py: 声明的struct,实现了具体的序列化和反序列化
    SERVICE_NAME.py: 对应service的描述文件,包含了:
        Iface: service接口定义
        Client: client的rpc调用桩
    

    用法

    Thrift的用法实际上很简单,定义好IDL,然后实现service对应的handler(方法名、参数列表与接口定义一致接口),最后就是选择各个组件。需要选择的包括:Transport(一般都是socket,只是十分需要选择buffed和framed装饰器factory),Protocol,Server。
    

    示例

    IDL文件

    /*
    thrift接口定义文件
    */
    service HelloService {
        string say(1:string msg)
    }

    在编辑好定义文件后, 运行如下命令,生成thrift文件。可把hello目录移到当前目录下,便于后面调用。

    thrift -r -gen py hello.thrift

    server

    # coding: utf-8
    """
    thrift_client.py
    """
    import socket
    import sys
    from hello import HelloService
    from hello.ttypes import *
    
    from thrift.transport import TSocket
    from thrift.transport import TTransport
    from thrift.protocol import TBinaryProtocol
    from thrift.server import TServer
    
    
    class HelloServiceHandler:
        def say(self, msg):
            ret = "Received: " + msg
            print ret
            return ret
    
    
    handler = HelloServiceHandler()
    processor = HelloService.Processor(handler)
    transport = TSocket.TServerSocket("localhost", 9090)
    tfactory = TTransport.TBufferedTransportFactory()
    pfactory = TBinaryProtocol.TBinaryProtocolFactory()
    
    server = TServer.TSimpleServer(processor, transport, tfactory, pfactory)
    
    print "Starting thrift server in python..."
    server.serve()
    print "done!"
    

    client

    # coding: utf-8
    """
    thrift_client.py
    """
    
    import sys
    from hello import HelloService
    
    from thrift import Thrift
    from thrift.transport import TSocket
    from thrift.transport import TTransport
    from thrift.protocol import TBinaryProtocol
    
    try:
        transport = TSocket.TSocket('localhost', 9090)
        transport = TTransport.TBufferedTransport(transport)
        protocol = TBinaryProtocol.TBinaryProtocol(transport)
        client = HelloService.Client(protocol)
        transport.open()
    
        print "client - say"
        msg = client.say("Hello!")
        print "server - " + msg
    
        transport.close()
    
    except Thrift.TException, ex:
        print "%s" % (ex.message)
    

    运行结果

    $ ptyhon thrift_client.py
    client - say
    server - Received: Hello!
    
    $ python thrift_server.py
    Starting thrift server in python...
    Received: Hello!

    小结

    本文只是一个简单的示例,在实际项目中,一般会基于zookeeper来注册和管理服务的thrift状态,并对server和client进一步封装,便于在项目各个模块中调用。

    参考

    1. Python thrift使用示例
    2. https://thrift.apache.org/docs/concepts

关键字