thrift的简单使用
1 关于RPC和Thrift框架
RPC框架
就是编程人员在同一台机器的不同进程之间
或者 不同的机器之间
进行远程调用代码
的工具
Thrift
是一种的 高效的RPC框架
,可以支持跨OS和编程语言.
支持多种 数据传输方式 transports (such as sockets, pipes, etc)
支持多种 数据格式 protocol (binary, JSON, even compressed)
protocol(协议层, 定义数据传输格式,可以为二进制或者XML等)
transport(传输层,定义数据传输方式,可以为TCP/IP传输,内存共享或者文件共享等)
例如:
在linux系统上面 搭建一个用C++写的服务,通过HTTP提供JSON-based的数据服务, 可以在window系统上使用 python编写的客户端的请求。 当然server 和 client 之间 通讯的文件是 thrift生成的 IDL
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)所列的参数,不指定会使用默认值。
TServer的子类包括:
TSimpleServer, TThreadedServer, TThreadPoolServer, TForkingServer, THttpServer, TNonblockingServer, TProcessPoolServer
TServer的serve方法用于开始服务,接收client的请求。
2 什么时候要选择使用 Thrift
1.高并发
2.请求和响应的数据传输量大
3.业务系统跨多种语言
注意:
一般HTTP请求通常都能够满足需求,而使用Thrift带来很多开发上的额外的工作量,一个简单的服务,
需要写 客户端代码,thrift接口定义 以及 服务器端的服务响应代码,简单的事情复杂化
3 Thrift windows下的安装部署 和 简单实现
安装部署 :
下载地址:http://archive.apache.org/dist/thrift/0.10.0/
安装:
创建thrift 家目录 (D:\thrift)
将下载的thrift-0.10.0.exe 重命名为thrift.exe
将thrift.exe 放在thrift 家目录下
在环境变量path中添加(D:\thrift)
测试:
thrift -version
-->>> Thrift version 0.11.0
简单实现:
Thrift的用法实际上很简单,定义好IDL,然后实现service对应的handler(方法名、参数列表与接口定义一致接口), 最后就是选择各个组件。需要选择的包括:Transport(一般都是socket,只是十分需要选择buffed和framed装饰器factory),Protocol,Server。
第1步: 写.thrift文件,也就是接口描述文件(Interface Description File);
第2步: 用Thrift compiler (thrift-0.9.1.exe) ,生成目标语言代码;
第3步: 服务器端程序引入thrift生成的代码,实现RPC业务代码。
第4步: 客户端引入代码,调用远程服务。
4 thrift 实现 go 和python 的 通讯
安装 配置 thrift ( 协议转换工具 Thrift compiler )
./configure && make
下载 相关的库和包
go thrift 库 go get git.apache.org/thrift.git/lib/go/thrift
python thrift 包 pip install thrift
这里要注意 包与编译器 版本的一致
(这里用的是thrift 0.10, go 对应的版本可以通过git tag 来控制)
定义协议文件 (字符转换大写的例子)
// Writing a .thrift file tutorial.thrift === (字符转换大写)
service HelloService{
string say(1:string msg)
}
生成 对应的开发包
Generate Thrift file to source code 生成对应的开发语言的 code
各种语言通讯相关
thrift -out ../.. --gen go tutorial.thrift
thrift -out ../.. --gen py tutorial.thrift
把通过thrift编译器生成的各种语言的对应开发包,放置到对应的环境中
go --- $GOPATH/src
python --- lib
开始编写 客户端与 服务端
1 python 的 服务端
import socket
import sys
from tutorial import HelloService
from tutorial.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("127.0.0.1",8098) // 传输器
tfactory = TTransport.TFramedTransportFactory()
pfactory = TBinaryProtocol.TBinaryProtocolFactory()
server = TServer.TSimpleServer(processor,transport,tfactory,pfactory) // 服务器
print("Starting thrift server in python ... ")
server.serve() // 启动服务器
print("Done!")
2 golang 的 客户端
package main
import (
"net"
"git.apache.org/thrift.git/lib/go/thrift"
"log"
"tutorial"
"fmt"
)
const (
HOST = "127.0.0.1"
PORT = "8098"
)
func main() {
tSocket,err := thrift.NewTSocket(net.JoinHostPort(HOST,PORT)) // 获取socket
if err != nil {
log.Fatalln("tScoket error ", err)
}
transportFactory := thrift.NewTFramedTransportFactory(thrift.NewTTransportFactory()) // 传输格式
transport := transportFactory.GetTransport(tSocket)
protocolFactory := thrift.NewTBinaryProtocolFactoryDefault() // 协议
client := tutorial.NewHelloServiceClientFactory(transport,protocolFactory)
if err := transport.Open(); err != nil {
log.Fatalln(err)
}
defer transport.Close()
//fmt.Println("client say")
d, err := client.Say("hello")
if err != nil {
log.Fatalln(err)
}
fmt.Println("server msg: " + d)
}
3 go 的服务端
package main
import (
"strings"
"tutorial"
"git.apache.org/thrift.git/lib/go/thrift"
"log"
"fmt"
)
type HelloServiceImpl struct {}
func (hsi *HelloServiceImpl) Say(data string) (ret string, err error) {
ret = strings.ToUpper(data)
fmt.Println("Recieved :" + data)
return ret, nil
}
const (
HOST = "localhost"
PORT = "8099"
)
func main() {
handler := &HelloServiceImpl{} // 实例化一个 处理器对象
processor := tutorial.NewHelloServiceProcessor(handler)
//
serverTransport, err := thrift.NewTServerSocket(HOST+":"+PORT)
if err != nil {
log.Fatalln(err)
}
transportFactory := thrift.NewTFramedTransportFactory(thrift.NewTTransportFactory()) // 服务端 客户端 需要对应
//transportFactory := thrift.NewTBufferedTransportFactory(10000000)
// 传输器
protocolFactory := thrift.NewTBinaryProtocolFactoryDefault()
// 传输协议
server := thrift.NewTSimpleServer4(processor,serverTransport,transportFactory,protocolFactory)
fmt.Println("Running at : ", HOST + ":" + PORT)
server.Serve()
}
4 python 客户端
import sys
from tutorial import HelloService
from thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
try:
tsocket = TSocket.TSocket("localhost",8099)
transportFactory = TTransport.TFramedTransportFactory()
transport = transportFactory.getTransport(tsocket)
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 as ex:
pass