> Linux新闻 >

facebook thrift框架讲解

摘要: facebook thrift框架讲解

简介

       thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发。它结合了功能强大的软件堆栈代码生成引擎,以构建在 C++, Java, Go,Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 这些编程语言间无缝结合的、高效的服务 。

       thrift最初由facebook开发,07年四月开放源码,08年5月进入apache孵化器。 thrift 允许你定义一个简单的定义文件中的数据类型和服务接口。以作为输入文件,编译器生成代码用来方便地生成RPC客户端和服务器通信的无缝跨编程语言。看到这里,感觉thrift的作用与webservice差不多,webservice使用xml文件传输,文件太大,效率不高,thrift使用二进制数据,效率更高!

Thrift 主要由5个部分组成:

  • 类型系统以及 IDL(interface definition language) 编译器:负责由用户给定的 IDL 文件生成相应语言的接口代码

  • TProtocol:实现 RPC 的协议层,可以选择多种不同的对象串行化方式,如 JSON, Binary。

  • TTransport:实现 RPC 的传输层,同样可以选择不同的传输层实现,如socket, 非阻塞的 socket, MemoryBuffer 等。

  • TProcessor:作为协议层和用户提供的服务实现之间的纽带,负责调用服务实现的接口。

  • TServer:聚合 TProtocol, TTransport 和 TProcessor 几个对象。

上述的这5个部件都是在 Thrift 的源代码中通过为不同语言提供库来实现的,这些库的代码在 Thrift 源码目录的 lib 目录下面,在使用 Thrift 之前需要先熟悉与自己的语言对应的库提供的接口。

下图描绘了Thrift的整体架构,分为6个部分:

1.你的业务逻辑实现(You Code) 

2.客户端和服务端对应的Service

3.执行读写操作的计算结果

4.TProtocol 

5.TTransports 

6.底层I/O通信

a2a418e4-d899-38ab-9531-99809e3cb6f5.png

图 中前面3个部分是:

1、你通过Thrift脚本文件生成的代码

2、图中的褐色框部分是你根据生成代码构建的客户端和处理器的代码

3、图中红色的部分是两端产生的计算结果

从TProtocol下面3个部分是Thrift的传输体系和传输协议以及底层I/O通信,Thrift并且提供 堵塞、非阻塞,单线程、多线程的模式运行在服务器上,还可以配合服务器/容器一起运行,可以和现有JEE服务器/Web容器无缝的结合。

服务端和客户端具体的调用流程如下:

该图所示是 HelloServiceServer 启动的过程以及服务被客户端调用时,服务器的响应过程。从图中我们可以看到,程序调用了 TThreadPoolServer 的 serve 方法后,server 进入阻塞监听状态,其阻塞在 TServerSocket 的 accept 方法上。当接收到来自客户端的消息后,服务器发起一个新线程处理这个消息请求,原线程再次进入阻塞状态。在新线程中,服务器通过 TBinaryProtocol 协议读取消息内容,调用 HelloServiceImpl 的 helloVoid 方法,并将结果写入 helloVoid_result 中传回客户端。

该图所示是 HelloServiceClient 调用服务的过程以及接收到服务器端的返回值后处理结果的过程。从图中我们可以看到,程序调用了 Hello.Client 的 helloVoid 方法,在 helloVoid 方法中,通过 send_helloVoid 方法发送对服务的调用请求,通过 recv_helloVoid 方法接收服务处理请求后返回的结果。

数据类型

Thrift 脚本可定义的数据类型包括以下几种类型:

基本类型:

bool:布尔值,true 或 false,对应 Java 的 boolean

byte:8 位有符号整数,对应 Java 的 byte

i16:16 位有符号整数,对应 Java 的 short

i32:32 位有符号整数,对应 Java 的 int

i64:64 位有符号整数,对应 Java 的 long

double:64 位浮点数,对应 Java 的 double

string:未知编码文本或二进制字符串,对应 Java 的 String

结构体类型:

struct:定义公共的对象,类似于 C 语言中的结构体定义,在 Java 中是一个 JavaBean

容器类型:

list:对应 Java 的 ArrayList

set:对应 Java 的 HashSet

map:对应 Java 的 HashMap

异常类型:

exception:对应 Java 的 Exception

服务类型:service:对应服务的类

协议

  Thrift可以让你选择客户端与服务端之间传输通信协议的类别,在传输协议上总体上划分为文本(text)和二进制(binary)传输协议, 为节约带宽,提供传输效率,一般情况下使用二进制类型的传输协议为多数,但有时会还是会使用基于文本类型的协议,这需要根据项目/产品中的实际需求:
    * TBinaryProtocol – 二进制编码格式进行数据传输。

Factory proFactory = new TBinaryProtocol.Factory();

    * TCompactProtocol – 高效率的、密集的二进制编码格式进行数据传输

TCompactProtocol.Factory proFactory = new TCompactProtocol.Factory();

    * TJSONProtocol – 使用JSON的数据编码协议进行数据传输。

TJSONProtocol.Factory proFactory = new TJSONProtocol.Factory();

    * TSimpleJSONProtocol – 只提供JSON只写的协议,适用于通过脚本语言解析
    * TDebugProtocol – 在开发的过程中帮助开发人员调试用的,以文本的形式展现方便阅读

传输层
    * TSocket- 使用塞式I/O进行传输,也是最常见的模式。
    * TFramedTransport- 使用非阻塞方式,按块的大小,进行传输,类似于Java中的NIO。
    * TFileTransport- 顾名思义按照文件的方式进程传输,虽然这种方式不提供Java的实现,但是实现起来非常简单。
    * TMemoryTransport- 使用内存I/O,就好比Java中的ByteArrayOutputStream实现。
    * TZlibTransport- 使用执行zlib压缩,不提供Java的实现。

服务端类型
    * TSimpleServer -  单线程服务器端使用标准的塞式I/O。
    * TThreadPoolServer -  多线程服务器端使用标准的塞式I/O。
    * TNonblockingServer -  多线程服务器端使用非塞式I/O,并且实现了Java中的NIO通道。

下载thrift

      现在windows版本进行测试,目前最新的版本地址:http://apache.fayea.com/thrift/0.9.3/thrift-0.9.3.exe。

编写thrift
 

namespace java com.demo.thrift
service HelloService{
 
 void helloVoid(1: string arg)
 
}
thrift-0.9.3.exe -r -gen java hello_service.thrift

执行命令生成java代码文件夹

生成一个HelloService.java文件,内容太多就不贴代码了。

编写一个HelloServiceImpl实现HelloService.Iface里面接口

package com.demo.thrift;

public class HelloServiceImpl implements HelloService.Iface {
   
    public void helloVoid(String arg) throws org.apache.thrift.TException{
    System.out.println("hello " + arg);
    }

}

server代码:

package com.demo.thrift;

import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TBinaryProtocol.Factory;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TThreadPoolServer;
import org.apache.thrift.server.TThreadPoolServer.Args;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TTransportException;

public class HelloServiceServer {
    public void startServer() {
        try {
            TServerSocket serverTransport = new TServerSocket(1234);
            HelloService.Processor process = new HelloService.Processor(new HelloServiceImpl());
            Factory portFactory = new TBinaryProtocol.Factory(true, true);
            Args args = new Args(serverTransport);
            args.processor(process);
            args.protocolFactory(portFactory);
            TServer server = new TThreadPoolServer(args);
            server.serve();
        } catch (TTransportException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        HelloServiceServer server = new HelloServiceServer();
        server.startServer();
    }
}

client代码:

package com.demo.thrift;

import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException;

public class HelloServiceClient {

    public void startClient() {
        TTransport transport;
        try {
            transport = new TSocket("localhost", 1234);
            TProtocol protocol = new TBinaryProtocol(transport);
            HelloService.Client client = new HelloService.Client(protocol);
            transport.open();
            client.helloVoid("world");
            transport.close();
        } catch (TTransportException e) {
            e.printStackTrace();
        } catch (TException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        HelloServiceClient client = new HelloServiceClient();
        client.startClient();
    }
}

 




(责任编辑:IT)