python thrift使用实例

前言

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。

示例

简单记录下在mac下使用python thrift的过程

1. 安装 Thrift 的 python 库有两种方案(1. pip安装 2. 源码安装)具体参见文末链接

    1)pip安装: pip install thrift(最好在venv中使用)

2. 安装 Thrift 的 IDL 编译工具(windows/linux安装见文末链接)

    1)mac下安装: brew install thrift

    $ thrift -version,如果打印出来:Thrift version x.x.x 表明 complier 安装成功

3. 建立项目目录(thrift_demo)并开始编码

    1)目录结构

       

       <1> client目录下的 client.py 实现了客户端用于发送数据并打印接收到 server 端处理后的数据

       <2> server 目录下的 server.py 实现了服务端用于接收客户端发送的数据,并对数据进行大写处理后返回给客户端

       <3> thrift_file 用于存放 thrift 的 IDL 文件: *.thrift

   2) 定义 Thrift RPC 接口IDL文件 example.thrift:

namespace py example

struct Data {
    1: string text
    2: i32 id
}

service format_data {
    Data do_format(1:Data data),
}

进入 thrift_file 目录执行:$ thrift -out .. --gen py example.thrift,就会在 thrift_file 的同级目录下生成 python 的包:example

  3) 实现 server 端server.py:

#! /usr/bin/env python
# -*- coding: utf-8 -*-

import os
import sys
cur_path =os.path.abspath(os.path.join(os.path.dirname('__file__'), os.path.pardir))
sys.path.append(cur_path)

from example import format_data
from example import ttypes
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from thrift.server import TServer

__HOST = 'localhost'
__PORT = 9000


class FormatDataHandler(object):
    def do_format(self, data):
        print(data.text, data.id)
        # can do something
        return ttypes.Data(data.text.upper(), data.id)


if __name__ == '__main__':
    handler = FormatDataHandler()

    processor = format_data.Processor(handler)
    transport = TSocket.TServerSocket(__HOST, __PORT)
    tfactory = TTransport.TBufferedTransportFactory()
    pfactory = TBinaryProtocol.TBinaryProtocolFactory()

    rpcServer = TServer.TSimpleServer(processor,transport, tfactory, pfactory)

    print('Starting the rpc server at', __HOST,':', __PORT)
    rpcServer.serve()
    print('done')

  4) 实现 client 端client.py:

#! /usr/bin/env python
# -*- coding: utf-8 -*-

import os
import sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname('__file__'), os.path.pardir)))

from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from example.format_data import Client
from example.format_data import Data


__HOST = 'localhost'
__PORT = 9000


try:
    tsocket = TSocket.TSocket(__HOST, __PORT)
    transport = TTransport.TBufferedTransport(tsocket)
    protocol = TBinaryProtocol.TBinaryProtocol(transport)
    client = Client(protocol)

    data = Data('hello,world!', 123)
    transport.open()
    print('client-requets')
    res = client.do_format(data)
    # print(client.do_format(data).text)
    print('server-answer', res)

    transport.close()
except Thrift.TException as ex:
    print(ex.message)

4. 执行验证结果

    1) 先启动 server(进入server目录,执行python server.py),之后再另一个窗口执行 client(进入client目前,执行python client.py):

     client 侧控制台打印的结果为:

     

    server侧控制台打印的结果为:

    

    证明 Thrift 的 RPC 接口定义成功

参考:

Python RPC 之 Thrift(含thrift及thrift IDL如何安装)

Python Thrift示例

猜你喜欢

转载自www.cnblogs.com/276815076/p/10078645.html