python-thrift使用实例
前言
Apache Thrift 是 Facebook 实现的一种高效的、支持多种编程语言的远程服务调用的框架。本文将从 Python开发人员角度简单介绍 Apache Thrift 的架构、开发和使用。
Thrift简介
Transport
1 | Transport网络读写(socket,http等)抽象,用于和其他thrift组件解耦。 |
Protocol
1 | Protocol用于对数据格式抽象,在rpc调用时序列化请求和响应。 |
Processor
1 | Processor对stream读写抽象,最终会调用用户编写的handler已响应对应的service。具体的Processor有compiler生成,用户需要实现service的实现类。 |
Server
1 | Server创建Transport,输入、输出的Protocol,以及响应service的handler,监听到client的请求然后委托给processor处理。 |
Code generated
1 | constants.py: 包含声明的所有常量 |
用法
Thrift的用法实际上很简单,定义好IDL,然后实现service对应的handler(方法名、参数列表与接口定义一致接口),最后就是选择各个组件。
需要选择的包括:Transport(一般都是socket,只是十分需要选择buffed和framed装饰器factory),Protocol,Server。
示例
简单记录下在mac下使用python thrift的过程
安装 Thrift 的 python 库有两种方案(1. pip安装 2. 源码安装)具体参见文末链接
1)pip安装: pip install thrift(最好在venv中使用)安装 Thrift 的 IDL 编译工具(windows/linux安装见文末链接)
1)mac下安装: brew install thrift
$ thrift -version,如果打印出来:Thrift version x.x.x 表明 complier 安装成功建立项目目录(thrift_demo)并开始编码
1)目录结构(example目录及其下的文件不用手动创建,是通过命令自动生成的,具体细节请往下看)
<1> client目录下的 client.py 实现了客户端用于发送数据并打印接收到 server 端处理后的数据
<2> server 目录下的 server.py 实现了服务端用于接收客户端发送的数据,并对数据进行大写处理后返回给客户端
<3> thrift_file 用于存放 thrift 的 IDL 文件: *.thrift
2) 定义 Thrift RPC 接口IDL文件 example.thrift:1
2
3
4
5
6
7
8
9
10
11
12namespace py example
struct Data {
1: string name
2: i32 age
3: string addr
4: i32 code = 20
}
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:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34#! /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) 实现 client 端client.py:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43#! /usr/bin/env python
# -*- coding: utf-8 -*-
"""
@author: shuke
@file: client.py
@time: 2019/04/03 19:01
@contact: zhaofengfeng@wecash.net
@software: learn
"""
# ! /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 import Thrift
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('shuke', 18, "BeiJing", code=200)
transport.open()
print('client-requets')
res = client.do_format(data)
# print(client.do_format(data).text)
print('server-answer', res, "\n", res.__dict__)
transport.close()
except Thrift.TException as ex:
print(ex.message)执行验证结果
1) 先启动 server(进入server目录,执行python server.py),之后再另一个窗口执行 client(进入client目前,执行python client.py):client 侧控制台打印的结果为:1
2
3
4$ python client.py
client-requets
server-answer Data(name='SHUKE_Thrift', age=18, addr='BeiJing', code=200)
{'name': 'SHUKE_Thrift', 'age': 18, 'addr': 'BeiJing', 'code': 200}server侧控制台打印的结果为:
1
2
3$ python server.py
Starting the rpc server at localhost : 9000
shuke 18 BeiJing 200证明 Thrift 的 RPC 接口定义成功.
扩展
传输协议
在传输协议上总体划分为文本和二进制 ,为节约带宽,提高传输效率,一般情况下使用二进制类型的传输协议为多数.
TBinaryProtocol — 二进制编码格式进行数据传输
TCompactProtocol — 高效率的、密集的二进制编码格式进行数据传输
TJSONProtocol — 使用 JSON 的数据编码协议进行数据传输
TSimpleJSONProtocol — 只提供 JSON 只写的协议,适用于通过脚本语言解析
TDebugProtocol – 使用易懂的可读的文本格式,以便于 debug数据传输
TSocket — 使用阻塞式 I/O 进行传输,是最常见的模式
TFramedTransport — 使用非阻塞方式,按块的大小进行传输
TNonblockingTransport — 使用非阻塞方式,用于构建异步客户端
TMemoryTransport – 将内存用于 I/O
TZlibTransport – 使用 zlib 进行压缩, 与其他传输方式联合使用
TFileTransport – 以文件形式进行传输服务端类型
TSimpleServer — 单线程服务器端使用标准的阻塞式 I/O
TThreadPoolServer —— 多线程服务器端使用标准的阻塞式 I/O
TNonblockingServer —— 多线程服务器端使用非阻塞式 I/O数据类型
Thrift 脚本可定义的数据类型包括以下几种类型:
- 基本类型:
- bool:布尔值,true 或 false
- byte:8 位有符号整数
- i16:16 位有符号整数
- i32:32 位有符号整数
- i64:64 位有符号整数
- double:64 位浮点数
- string:未知编码文本或二进制字符串
- 结构体类型:
- struct:定义公共的对象,类似于 C 语言中的结构体定义
- 容器类型:
- list:一系列 t1 类型的元素组成的有序表,元素可以重复
- set:一系列 t1 类型的元素组成的无序表,元素唯一
- map<t1,t2>:key/value 对(key 的类型是 t1 且 key 唯一,value 类型是 t2)
- 异常类型:
- exception 异常在语法和功能上类似于结构体,它在语义上不同于结构体—当定义一个 RPC 服务时,开发者可能需要声明一个远程方法抛出一个异常。
- 服务类型:
- service:对应服务的类
refs
python thrift使用实例-博客园
基于rpc通信的原理及python中的rpc框架 | nMask’s Blog
json-rpc · PyPI
zerorpc