L
L
LearnJava
Search…
⌃K

Thrift介绍

由于我们组要求使用的是Thrift0.8.0版本,下面以这个版本为例来讲解如何安装配置Thrift。

一、安装

tar -zxvf thrift-0.8.0.tar.gz
cd thrift-0.8.0
./configure --prefix=/usr/local/ --with-boost=/usr/local --with-libevent=/usr/local --without-csharp --without-erlang --without-go --without-haskell --without-ruby --without-cpp --without-perl --without-php --without-php_extension --without-python
make
sudo make install
# 检查是否安装成功,出现下面的情况说明已经正确安装
thrift -version
Thrift version 0.8.0

二、Thrift简介

Thrift是一个轻量级的、跨语言的远程服务调用框架。Thrift支持不同的编程语言,包括C++、Java、Python、PHP、Ruby等。

三、Thrift软件栈

Thrift软件栈从下到上依次是:传输层、协议层、处理层和服务层。
  • 传输层:TTransport,负责直接从网络读取和写入数据,定义了具体的网络传输协议,比如TCP/IP等;
  • 协议层:TProtocal,定义了数据传输格式,负责网络传输数据的序列化和反序列化,比如说json、XML、二进制数据等;
  • 处理层:TProcessor,处理层是由具体的IDL(接口描述语言)生成的,封装了具体的底层网络传输和序列化方式,并委托给用户实现的handler进行处理;
  • 服务层:TServer,整合上述组件,提供具体的网络线程/IO模型,形成最终的服务,然后接收Client的请求,并转到某个TProcessor上进行请求处理。
Thrift的传输层
创建的传输层有以下几种:
  1. 1.
    TSocket:使用阻塞式IO进行传输,是最常见的模式;
  2. 2.
    TNonblockingTransport:使用非阻塞方式,用于构建异步客户端
  3. 3.
    TFramedTransport:使用非阻塞方式,按块的大小进行传输,类似于Java中的NIO
  4. 4.
    TBufferedTransport:对某个Transport对象操作的数据进行buffer,即从buffer中读取数据进行传输,或者将数据直接写入buffer。
  5. 5.
    THttpTransport:采用Http传输协议进行数据传输。
  6. 6.
    TFileTransport:文件(日志)传输类,允许client将文件传给server,允许server将收到的数据写到文件中。
  7. 7.
    TZlibTransport:与其他的TTransport配合使用,压缩后对数据进行传输,或者将收到的数据解压
Thrift的服务端类型
  1. 1.
    TSimpleServer:单线程服务器端,使用标准的阻塞式I/O,只在演示的时候用,实际工作中很少用到;
  2. 2.
    TThreadPoolServer:多线程服务器端,使用标准的阻塞式I/O,主线程负责监听新连接,其他处理交给单独的线程池;
  3. 3.
    TNonblockingServer:单线程服务器端,使用非阻塞式I/O,一个线程循环处理监听socket,处理连接,读,写请求;
  4. 4.
    THsHaServer:半同步半异步服务器端,基于非阻塞式IO读写和多线程工作任务处理,对TNonblockingServer的优化,读请求以及后续的业务处理交给单独的线程池来做;
  5. 5.
    TThreadedSelectorServer:多线程选择器服务器端,对THsHaServer异步IO模型上进行增强,最高级的模式,大部分场景下性能都不会差,如果不知道选哪个就选这个。

四、Thrift数据类型

Thrift主要有下面5种类型:
1. 基本类型:
  • bool: 布尔值
  • byte: 8位有符号整数
  • i16: 16位有符号整数
  • i32: 32位有符号整数
  • i64: 64位有符号整数
  • double: 64位浮点数
  • string: UTF-8编码的字符串
  • binary: 二进制串
注意:Thrift不支持无符号整型,因为很多编程语言本身就不存在无符号整型,如java。
2. 结构体类型:
  • struct: 定义的结构体对象
3. 容器类型:
  • list: 有序元素列表
  • set: 无序无重复元素集合
  • map: 有序的key/value集合
4. 异常类型:
  • exception: 异常类型
5. 服务类型:
  • service: 具体对应服务的类
此外thrift还支持常量和枚举。

五、Thrift实战

5.1 编写IDL文件

hello.thrift
service HelloWorldService {
string say(1: string username)
}

5.2 编译IDL文件生成Java文件

thrift -gen java hello.thrift
于未指定代码生成的目标目录,生成的类文件默认存放在gen-java目录下。这里会生成4个重要的内部接口/类:
  • Iface服务端通过实现HelloWorldService.Iface接口,向客户端的提供具体的同步业务逻辑。
  • AsyncIface服务端通过实现HelloWorldService.Iface接口,向客户端的提供具体的异步业务逻辑。
  • Client客户端通过HelloWorldService.Client的实例对象,以同步的方式访问服务端提供的服务方法。
  • AsyncClient客户端通过HelloWorldService.AsyncClient的实例对象,以异步的方式访问服务端提供的服务方法。

5.3 代码实现

新建maven工程,pom中添加依赖
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.6.6</version>
</dependency>
<dependency>
<groupId>org.apache.thrift</groupId>
<artifactId>libthrift</artifactId>
<version>0.8.0</version>
</dependency>
</dependencies>
将生成的HelloWorldService.java源文件拷贝进项目源文件目录中,并实现HelloWorldService.Iface的定义的say()方法。
HelloWorldServiceImpl.java
import org.apache.thrift.TException;
public class HelloWorldServiceImpl implements HelloWorldService.Iface {
@Override
public String say(String username) throws TException {
return "Hello " + username;
}
}
服务端实现:SimpleServer.java
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.transport.TServerSocket;
import java.net.ServerSocket;
public class SimpleServer {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(9999);
TServerSocket serverTransport = new TServerSocket(serverSocket);
HelloWorldService.Processor processor =
new HelloWorldService.Processor<HelloWorldService.Iface>(new HelloWorldServiceImpl());
TBinaryProtocol.Factory protocolFactory = new TBinaryProtocol.Factory();
TSimpleServer.Args tArgs = new TSimpleServer.Args(serverTransport);
tArgs.processor(processor);
tArgs.protocolFactory(protocolFactory);
// 简单的单线程服务模型 一般用于测试
TServer tServer = new TSimpleServer(tArgs);
System.out.println("Running Simple Server");
tServer.serve();
}
}
客户端实现:SimpleClient.java
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;
public class SimpleClient {
public static void main(String[] args) {
TTransport transport = null;
try {
transport = new TSocket("127.0.0.1" , 9999, 5000);
TProtocol protocol = new TBinaryProtocol(transport);
HelloWorldService.Client client = new HelloWorldService.Client(protocol);
transport.open();
String result = client.say("nik");
System.out.println("Result =: " + result);
} catch (TException e) {
e.printStackTrace();
} finally {
if (null != transport) {
transport.close();
}
}
}
}
依次运行服务端和客户端会出现以下结果:
Running Simple Server
Result =: Hello nik

5.4 总结

从使用thrift的过程中可以总结thrift实现服务端和客户端逻辑的基本思路。
Thrift实现服务端:
  • 实现服务处理接口impl
  • 创建TProcessor
  • 创建TServerTransport
  • 创建TProtocol
  • 创建TServer
  • 启动Server
Thrift实现客户端:
  • 创建Transport
  • 创建TProtocol
  • 基于TTransport和TProtocol创建Client

六、遇到的问题

1. 运行时报错Class JavaLaunchHelper is implemented in both...
【错误描述】
idea run服务端的时候报错:objc[79886]: Class JavaLaunchHelper is implemented in both /Library/Java/JavaVirtualMachines/jdk1.7.0_80.jdk/Contents/Home/bin/java (0x106b914c0) and /Library/Java/JavaVirtualMachines/jdk1.7.0_80.jdk/Contents/Home/jre/lib/libinstrument.dylib (0x108e7e4e0). One of the two will be used. Which one is undefined.
【问题解决】
这是Mac版idea的一个bug,jdk1.8及以上已经修复了,因为项目要求是jdk1.7,并且这个错误不影响正常使用可以忽略不计了。
2. 启动server时报错SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
【错误描述】
启动server的时候报错:
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
【问题解决】
上面的意思是,在运行时,你没有做日志的实现(或者说日志的绑定),所以slf4j简简单单的使用了一个什么也不会做的空实现。 为了看到正确的输出,你应该尝试使用一个简单(simple)的实现,这个实现根本不需要任何配置!只要回到pom.xml然后添加如下配置:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.6.6</version>
</dependency>
参考:
【thrift概述与入门】https://juejin.im/post/6844903622380093447
【thrift基本原理】https://www.jianshu.com/p/5e3a4ab838a3