您的位置:首页 > 其它

thrift 小结

2016-03-10 14:00 274 查看

概述

Thrift是一个跨语言的服务部署框架,最初由Facebook于2007年开发,2008年进入Apache开源项目。Thrift通过一个中间语言(IDL, 接口定义语言)来定义RPC的接口和数据类型,然后通过一个编译器生成不同语言的代码(C++,Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk和OCaml),并由生成的代码负责RPC协议层和传输层的实现。

相关资料

official-github

thrift指南

thrift demo

thrift wiki

thrift-tutorial

thrift安装

windows

1.安装thrift.exe

2.配置maven,通过maven执行IDL生成代码工作

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion>

<groupId>thriftTest</groupId>
<artifactId>simplecConsole</artifactId>
<version>1.0-SNAPSHOT</version>

<name>thrift-demo-console</name>
<description>A maven project to study thrift.</description>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<compiler-plugin.version>2.3.2</compiler-plugin.version>
<thrift.version>0.9.3</thrift.version>
</properties>

<dependencies>
<dependency>
<groupId>org.apache.thrift</groupId>
<artifactId>libthrift</artifactId>
<version>${thrift.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.1</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
<configuration>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<!--   <plugin>
<groupId>org.apache.thrift.tools</groupId>
<artifactId>maven-thrift-plugin</artifactId>
<version>0.1.11</version>
<configuration>
<thriftExecutable>D:\Thrift\thrift.exe</thriftExecutable>
<generator>java</generator>
<outputDirectory>src/main/java/thrift/demo</outputDirectory>
<thriftSourceRoot>${project.basedir}/src/main/resources</thriftSourceRoot>
</configuration>
<executions>
<execution>
<id>thrift-sources</id>
<phase>generate-sources</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>thrift-test-sources</id>
<phase>generate-test-sources</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>-->
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>compile-thrift</id>
<phase>generate-sources</phase>
<configuration>
<tasks>
<mkdir dir="src/main/java/com/anjuke/demo/thrift/auto"/>
<path id="thrift.path">
<fileset dir="${project.basedir}/src/main/resources">
<include name="**/*.thrift"/>
</fileset>
</path>
<pathconvert pathsep=" " property="thrift.files"
refid="thrift.path"/>
<exec executable="D:\Thrift\thrift">
<arg value="-r --gen"/>
<arg value="java"/>
<arg value="-out"/>
<arg value="src/main/java"/>
<arg line="${thrift.files}"/>
</exec>
</tasks>
<sourceRoot>src/main/java/thrift/demo/thrift</sourceRoot>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<configuration>
<verbose>true</verbose>
<filesets>
<fileset>
<directory>${project.basedir}/src/main/java/com/anjuke/demo/thrift/auto</directory>
</fileset>
</filesets>
</configuration>
</plugin>
</plugins>
</build>

</project>


linux

ReferenceLink

基本概念

开发流程

定义thrift的IDL文件

生成对应语言的代码

代码生成服务的所有数据协议转换,并提供接口调用系统的传输方式(TSocket,THttpTransport,TFileTransport),以及同步\异步客户端,Processor负责Client请求的响应

实现服务端

有阻塞,非阻塞,线程池,半同步半异步,Selector多种服务端实现模式。

TSimpleServer – 简单的单线程服务模型,常用于测试
TThreadedServer – 多线程服务模型,使用阻塞式IO,每个请求创建一个线程。(java 不支持)
TThreadPoolServer – 多线程服务模型,使用标准的阻塞式IO,预先创建一组线程处理请求。
TThreadedSelectorServer 允许你用多个线程来处理网络I/O。它维护了两个线程池,一个用来处理网络I/O,另一个用来进行请求的处理
TNonblockingServer – 多线程服务模型,使用非阻塞式IO(需使用TFramedTransport数据传输方式),只有一个线程来处理消息
THsHaServer - 半同步半异步的服务模型,一个单独的线程用来处理网络I/O,一个worker线程池用来进行消息的处理


服务端流程

基于服务的具体实现类,实现processor

TProcessor tprocessor = new HelloWorldService.Processor<HelloWorldService.Iface>(
new HelloWorldImpl());


create 服务端socket(Transport)

TServerSocket 阻塞型socket, 用于服务器端, accecpt到的socket类型都是TSocket(即阻塞型socket);
TNonblockingServerSocket 非阻塞型socket, 用于服务器端(NIO)


create Protocol 必须与客户端的Protocol一致

基于以上信息create Server

对于客户端使用封装了基本TTransport的Transport的例如(TZlibTransport,TFramedTransport),需要对Server设置该TTransport的工厂类

Sever demo

TProcessor tprocessor = new HelloWorldService.Processor<HelloWorldService.Iface>(
new HelloWorldImpl());

TNonblockingServerSocket tnbSocketTransport = new TNonblockingServerSocket(
SERVER_PORT);
TNonblockingServer.Args tnbArgs = new TNonblockingServer.Args(
tnbSocketTransport);
tnbArgs.processor(tprocessor);
tnbArgs.transportFactory(new TFramedTransport.Factory());
tnbArgs.protocolFactory(new TCompactProtocol.Factory());

// 使用非阻塞式IO,服务端和客户端需要指定TFramedTransport数据传输的方式
TServer server = new TNonblockingServer(tnbArgs);
server.serve();


实现客户端

包括同步,异步两种客户端形式

客户端流程

create Socket

TSocket:采用TCP Socket进行数据传输,阻塞型socket,用于客户端,采用系统函数read和write进行读写数据;(BIO)
TNonblockingSocket (NIO) 异步客户端使用


create Transport

TSocket:采用TCP Socket进行数据传输,阻塞型socket,用于客户端,采用系统函数read和write进行读写数据;(BIO)
TNonblockingSocket (NIO) 异步客户端使用
TSSLSocket 继承TSocket,阻塞型socket, 用于客户端;采用openssl的接口进行读写数据。
THttpTransport:采用Http传输协议进行数据传输
TFileTransport – 以文件形式进行传输。
TMemoryTransport – 将内存用于I/O. java实现时内部实际使用了简单的ByteArrayOutputStream。
TZlibTransport – 使用zlib进行压缩, 与其他传输方式联合使用。当前无java实现。
TFramedTransport – 以frame为单位进行传输,非阻塞式服务中使用。类似于Java中的NIO。
TFastFramedTransport 与TFramedTransport相比,始终使用相同的Buffer,提高了内存的使用率。
TSaslClientTransport与TSaslServerTransport, 提供SSL校验


create Protocol must same as service based on transport

TBinaryProtocol – 二进制格式.
TCompactProtocol – 压缩格式
TDenseProtocol -继承TCompactProtocol,不包含meta信息
TJSONProtocol – JSON格式
TSimpleJSONProtocol –提供JSON只写协议, 生成的文件很容易通过脚本语言解析。


create Client based on Transport and Protocol

open transport

client.method call service

client demo

transport = new TSocket(SERVER_IP, SERVER_PORT, TIMEOUT);
// 协议要和服务端一致
TProtocol protocol = new TBinaryProtocol(transport);
HelloWorldService.Client client = new HelloWorldService.Client(protocol);
transport.open();
String result = client.sayHello(userName);


async client demo

TAsyncClientManager clientManager = new TAsyncClientManager();
TNonblockingTransport transport = new TNonblockingSocket(SERVER_IP,SERVER_PORT, TIMEOUT);

TProtocolFactory tprotocol = new TCompactProtocol.Factory();
HelloWorldService.AsyncClient asyncClient = new HelloWorldService.AsyncClient(tprotocol, clientManager, transport);
System.out.println("Client start .....");

CountDownLatch latch = new CountDownLatch(1);
AsynCallback callBack = new AsynCallback(latch);
System.out.println("call method sayHello start ...");
asyncClient.sayHello(userName, callBack);
System.out.println("call method sayHello .... end");
boolean wait = latch.await(30, TimeUnit.SECONDS);


Thrift框架

框架和时序图

thrift Type

base type

bool: 布尔值 (true or false), one byte

byte: 有符号字节

i16: 16位有符号整型

i32: 32位有符号整型

i64: 64位有符号整型

double: 64位浮点型

string: 编码无关的文本

struct

struct是定义为一种对象,和面向对象语言的class差不多.,但是struct有以下一些约束:

struct不能继承,但是可以嵌套,不能嵌套自己。

其成员都是有明确类型

成员是被正整数编号过的,其中的编号使不能重复的,这个是为了在传输过程中编码使用。

成员分割符可以是逗号(,)或是分号(;),而且可以混用,但是为了清晰期间,建议在定义中只使用一种,比如C++学习者可以就使用分号(;)。

字段会有optional和required之分和protobuf一样,但是如果不指定则为无类型—可以不填充该值,但是在序列化传输的时候也会序列化进去,optional是不填充则部序列化,required是必须填充也必须序列化。

每个字段可以设置默认值

同一文件可以定义多个struct,也可以定义在不同的文件,进行include引入。

struct demo

struct Report
{
1: required string msg, //改字段必须填写
2: optional i32 type = 0; //默认值
3: i32 time //默认字段类型为optional
}


Containers

如protobuf 通过 repeated 标识实现 Containers 不同

list<t>: 元素类型为t的有序表,容许元素重复。对应c++的vector,java的ArrayList或者其他语言的数组(官方文档说是ordered list不知道如何理解?排序的?c++的vector不排序

set<t>:元素类型为t的无序表,不容许元素重复。对应c++中的set,java中的HashSet,python中的set,php中没有set,则转换为list类型了

map<t,t>: 键类型为t,值类型为t的kv对,键不容许重复。对用c++中的map, Java的HashMap, PHP 对应 array, Python/Ruby 的dictionary。

Container demo

struct Test {
1: map<Numberz, UserId> user_map,
2: set<Numberz> num_sets,
3: list<Stusers> users
}


Enum

不同于protocal buffer,thrift不支持枚举类嵌套,枚举常量必须是32位的正整数

编译器默认从0开始赋值

可以赋予某个常量某个整数

允许常量是十六进制整数

末尾没有分号

给常量赋缺省值时,使用常量的全称

Enumeration demo

enum EnOpType {
CMD_OK = 0, // (0)   
CMD_NOT_EXIT = 2000, // (2000)
CMD_EXIT = 2001, // (2001)    
CMD_ADD = 2002 // (2002)
}

struct StUser {
1: required i32 userId;
2: required string userName;
3: optional EnOpType cmd_code = EnOpType.CMD_OK; // (0)
4: optional string language = “english”
}


Exception

Thrift结构体将会被转换成面向对象语言的类。异常在语法和功能上类似于结构体,差别是异常使用关键字exception,而且异常是继承每种语言的基础异常类。

Exception demo

exception Extest {
1: i32 errorCode,
2: string message,
3: StUser userinfo
}


Services

服务的定义方法在语义(semantically)上等同于面向对象语言中的接口。Thrift编译器会产生执行这些接口的client和server stub。具体参见下一节。在流行的序列化/反序列化框架(如protocal buffer)中,Thrift是少有的提供多语言间RPC服务的框架。这是Thrift的一大特色。

services demo

service SeTest {
void ping(),
bool postTweet(1: StUser user);
StUser searchTweets(1:string name);
oneway void zip()

}


Namespace

Thrift中的命名空间类似于C++中的namespace和java中的package,它们提供了一种组织(隔离)代码的简便方式。名字空间也可以用于解决类型定义中的名字冲突。

Namespace demo

namespace cpp com.example.test
namespace java com.example.test
namespace php com.example.test


Includes

便于管理、重用和提高模块性/组织性,常常分割Thrift定义在不同的文件中。包含文件搜索方式与c++一样。Thrift允许文件包含其它thrift文件,用户需要使用thrift文件名作为前缀访问被包含的对象

Include demo

include "test.thrift"
...
struct StSearchResult {
1: in32 uid;
...
}


Thrift IDL

基于Thrift Type 书写IDL,文件后缀名thrift

IDL demo

struct User{
1:i64 id,
2:string name,
3:i64 timestamp,
4:bool vip
}

service UserService{
User getById(1:i64 id)
}


My demo

demo-github-link
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: