thrift的简单使用

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


Buy me a 肥仔水!