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-githubthrift指南
thrift demo
thrift wiki
thrift-tutorial
thrift安装
windows
1.安装thrift.exe2.配置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线程池用来进行消息的处理
服务端流程
基于服务的具体实现类,实现processorTProcessor 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 SocketTSocket:采用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 bytebyte: 有符号字节
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,文件后缀名thriftIDL 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相关文章推荐
- 如此之笨 storyboard里找view
- 未使用的变量不报警告
- 正则表达式 - 运算符优先级
- 关于toolbar的menu显示icon问题
- 多台web服务器之间共享session
- ubuntu开机自启动vitrualbox中的虚拟机
- iOS-生成plist文件,在项目中代码创建plist
- 正则表达式 - 元字符
- Codeforces Round #273 (Div. 2)(C)贪心,思维
- http客户端通信 (java原生)
- 添加远程库
- opencv CvMat转Mat
- hihoCoder 1032 最长回文子串(Manacher算法)
- 曾经困扰过我的sql
- angularjs flask跨域问题 XMLHttpRequest cannot load. No 'Access-Control-Allow-Origin'
- 移植OpenWrt到CuHead Pro WiFi
- 正则表达式 - 语法
- 【ActionBar的使用】
- 安卓之检测网络
- Android中的颜色设置