前言

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)目录结构(example目录及其下的文件不用手动创建,是通过命令自动生成的,具体细节请往下看)

<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)
# 传输方式,使用buffer
tfactory = TTransport.TBufferedTransportFactory()
# 传输的数据类型:二进制
pfactory = TBinaryProtocol.TBinaryProtocolFactory() # 创建一个thrift 服务
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 接口定义成功

================================部分详细介绍========================================

传输协议

在传输协议上总体划分为文本和二进制 ,为节约带宽,提高传输效率,一般情况下使用二进制类型的传输协议为多数.

  • 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:对应服务的类

参考:

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

Python Thrift示例

thrift Python Tutorial

Thrift network stack

Thrift Tutorial

Thrift 应用总结

python thrift使用实例的更多相关文章

  1. python thrift 实现 单端口多服务的过程

    Thrift 是一种接口描述语言和二进制通信协议.以前也没接触过,最近有个项目需要建立自动化测试,这个项目之间的微服务都是通过 Thrift 进行通信的,然后写自动化脚本之前研究了一下. 需要定义一个 ...

  2. python 类和实例

    面向对象最重要的概念就是类(Class)和实例(Instance),必须牢记类是抽象的模板,比如Student类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可 ...

  3. Python Thrift 简单示例

    本文基于Thrift-0.10,使用Python实现服务器端,使用Java实现客户端,演示了Thrift RPC调用示例.Java客户端提供两个字符串参数,Python服务器端计算这两个字符串的相似度 ...

  4. python第六天 函数 python标准库实例大全

    今天学习第一模块的最后一课课程--函数: python的第一个函数: 1 def func1(): 2 print('第一个函数') 3 return 0 4 func1() 1 同时返回多种类型时, ...

  5. Python 解析XML实例(xml.sax)

    已知movies.xml <collection shelf="New Arrivals"> <movie title="Enemy Behind&qu ...

  6. Python操作Mysql实例代码教程在线版(查询手册)_python

    实例1.取得MYSQL的版本 在windows环境下安装mysql模块用于python开发 MySQL-python Windows下EXE安装文件下载 复制代码 代码如下: # -*- coding ...

  7. python连接mysql实例分享_python

    示例一 #coding=UTF-8 import sys import MySQLdb import time reload(sys) sys.setdefaultencoding('utf-8') ...

  8. 4. python 修改字符串实例总结

    4. python 修改字符串实例总结 我们知道python里面字符串是不可原处直接修改的,为了是原来的字符串修改过来,我们有一下方法: 1.分片和合并 >>> a='abcde'  ...

  9. python类和实例以及__call__/__del__

    面向对象最重要的概念就是类(Class)和实例(Instance),必须牢记类是抽象的模板,比如Student类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可 ...

随机推荐

  1. CSS 2. 盒模型|浮动

    1.盒模型 盒模型: 在网页中 基本上都会显示一些方方正正的盒子,这种盒子就被我们称为盒模型.重要的属性: width,height,padding,border, margin 盒子模型通过四个边界 ...

  2. 040 关于hive元数据的解析

    一:原理 1.整体原理 找到数据库 找到表 先找分区表,然后不找SDS表了,先去找PARTITIONS表,根据这张表的SD_ID找对应的HDFS路劲 再普通表,直接根据SDS表的中SD_ID找到对应的 ...

  3. 《Gradle权威指南》--Java Gradle插件

    No1: dependencies{ compile group: 'com.squareup.okhttp3',name:'okhttp',version:'3.0.1' } //缩写 depend ...

  4. 《Gradle权威指南》--Groovy基础

    No1: Groovy中分号不是必须的 No2: Groovy中,单引号和双引号都可以定义一个字符串常量,不同的是单引号标记的是纯粹的字符串常量,而不是对字符串里的表达式做运算,但是双引号可以. ta ...

  5. HDU1789 Doing Homework again 做作业【贪心】

    题目链接:https://vjudge.net/problem/HDU-1789 题目大意: 给出N个作业的截至日期,和N个作业不交所扣掉的分数,要求输出扣除分数做少的方案. 解析: 与上一道销售商品 ...

  6. Python爬虫之正则表达式的使用(三)

    正则表达式的使用 re.match(pattern,string,flags=0) re.match尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none 参数 ...

  7. window10 还原精灵 破解版 冰点

    韩梦飞沙  韩亚飞  313134555@qq.com  yue31313  han_meng_fei_sha=======

  8. activate-power-mode 插件 安装 设置 IDEA

    作者:韩梦飞沙 Author:han_meng_fei_sha 邮箱:313134555@qq.com E-mail: 313134555 @qq.com 可用 摇 shake 粒子 particle ...

  9. Python3基础系列——枚举类型大揭秘

    为什么使用枚举 枚举类型是定义常量的一种最优选择. 常量的广义概念是:不变化的量 对于常量的通俗比喻--如同大山不被轻而易举地改变 地球上的重力加速度到海枯石烂也会改变 人们使用的常量是时间不很漫长的 ...

  10. Python问题之“NameError: name 'reload' is not defined”

    出现这个错误的原因是你使用的Python版本已经不再使用了 在Python2.x中会用到reload来解决中文乱码问题 import sys reload(sys) sys.setdefaultenc ...