简介
Thrift是一个RPC框架,由facebook开发,07年四月开放源码,08年5月进入Apache孵化器。它支持可扩展且跨语言的服务的开发,它结合了功能强大的软件堆栈和代码生成引擎,以构建在C++、Java、Python、PHP、Ruby、Erlang、Perl、Haskell、C#、Cocoa、JavaScript、Node.js、Smalltalk and OCaml等等编程语言间无缝结合的、高效的服务。Thrift允许你定义一个简单的定义文件中的数据类型和服务接口。以作为输入文件,编译器生成代码用来方便地生成RPC客户端和服务器通信的无缝跨编程语言。
基本结构
- Transport层:抽象了数据在网络中的传输。
- Protocol层:定义了数据的序列化、反序列化方式。常用的格式有:二进制、压缩格式和json格式。
- Processor层:Thrift中最关键的一层,它包括thrift文件生成的接口,以及这些接口应对的实现。
- Server层:将所有这些(Transport、Protocol与Processor)封装在一起,对外提供服务。
例子
Thrift的安装
brew install thrift
项目结构
├── pom.xml ├── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ └── thrift │ │ │ ├── client │ │ │ │ └── Client.java │ │ │ ├── demo │ │ │ │ ├── HelloWorldImpl.java │ │ │ │ └── HelloWorldService.java │ │ │ └── server │ │ │ └── Server.java │ │ ├── resources │ │ └── thrift │ │ └── HelloWorld.thrift │ └── test │ └── java
首先创建thrift文件夹及其路径下的HelloWorld.thrift,内容如下:
namespace java com.thrift.demo
service HelloWorldService {
string sayHello(1:string usrename);
} 随后在thrift下启动终端并输入:
thrift --gen java HelloWorld.thrift
随后在原地生成com.thrift.demo.HelloWorldService.java,我们将其放到java路径下并新建两个包server与client。
感兴趣可以观察一下HelloWorldService.java的内容,竟然自动生成了近900行的代码。
随后在com.thrift.demo包下新建HelloWorldImpl,这个是我们实现业务逻辑的类。
package com.thrift.demo;
import org.apache.thrift.TException;
public class HelloWorldImpl implements HelloWorldService.Iface{
public HelloWorldImpl() {}
public String sayHello(String usrename) throws TException {
return "Hi,"+usrename+"Welcome to my website";
}
} 值得注意的是,这个类实现了生成的HelloWorldService下的一个子接口。随后将方法补全。
下面给出Server以及Client的实现逻辑,解释内容以注释的形式给出:
package com.thrift.server;
import com.thrift.demo.HelloWorldImpl;
import com.thrift.demo.HelloWorldService;
import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.transport.TServerSocket;
public class Server {
public final static int SERVER_PORT = 7099;
private static String SERVER_IP = "localhost";
public static void startServer() {
try {
System.out.println("HelloWorld Server start...");
// 定义ServerSocket
TServerSocket serverSocket = new TServerSocket(SERVER_PORT);
// 定义参数对象并绑定到ServerSocket
TServer.Args args = new TServer.Args(serverSocket);
/* HelloWorldService.Processor在定义时实现了org.apache.thrift.TProcessor,其构造函数需要传入一个iFace
* 即我们的具体需求实现
*/
TProcessor processor = new HelloWorldService.Processor(new HelloWorldImpl());
// 定义一个处理二进制协议的工厂
TBinaryProtocol.Factory portFactory = new TBinaryProtocol.Factory(true, true);
// 参数绑定处理器以及工厂
args.processor(processor);
args.protocolFactory(portFactory);
// 定义工厂,还有TThreadPoolServer的线程池版本
TServer server = new TSimpleServer(args);
// 启动服务
server.serve();
}
catch (Exception e) {
System.out.println("Server start error");
e.printStackTrace();
}
}
public static void main(String[] args) {
Server.startServer();
}
} package com.thrift.client;
import com.thrift.demo.HelloWorldService;
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 Client {
public static final int SERVER_PORT = 7099;
public static final String SERVER_IP = "localhost";
public static void startClient(String username) {
// 定义一个运输层实体
TTransport tTransport = null;
try {
// 绑定ip和端口
tTransport = new TSocket(SERVER_IP, SERVER_PORT);
// 定义对应的协议
TProtocol protocol = new TBinaryProtocol(tTransport);
// 生成对应的客户端并绑定协议
HelloWorldService.Client client = new HelloWorldService.Client(protocol);
// 打开实体
tTransport.open();
// 进行远程调用
String result = client.sayHello(username);
System.out.println("Thrift client result=" + result);
Thread.sleep(2000);
}
catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Client.startClient("zhouxiang");
}
} 测试
先运行Server,再运行Client可从控制台观察到结果:
Thrift client result=Hi,zhouxiangWelcome to my website
Thrift支持的协议
Thrift可以让你选择客户端与服务端之间数据的传输通信协议,但要保证客户端和服务端的协议一致。在传输协议上总体上划分为文本和二进制传输协议,为节约带宽和提高传输效率,一般情况下使用二进制类型的传输协议较多,但有时会还是会使用基于文本类型的协议,这需要根据实际需求来看。
- TBinaryProtocol:二进制编码格式进行数据传输
- TCompactProtocol:这种协议非常有效,使用Variable-Length Quantity (VLQ) 编码对数据进行压缩
- TJSONProtocol:使用JSON的数据编码协议进行数据传输
- TSimpleJSONProtocol:这种节约只提供JSON只写的协议,适用于通过脚本语言解析
- TDebugProtocol:在开发的过程中帮助开发人员调试用的,以文本的形式展现方便阅读
Thrift支持的服务端
Thrift在服务端提供了很多不同类型的选择:
- TSimpleServer:TSimpleServer是单线程阻塞IO的实现,仅适用于demo
- TThreadPoolServer:顾名思义,TThreadPoolServer内部使用一个线程池来处理客户端的请求。它使用一个专门的线程来接收请求,一旦接收到请求就会放入ThreadPoolExecutor中的一个线程池处理,性能表现优异
- TNonblockingServer:单线程非阻塞IO的实现,通过java.nio.channels.Selector的select()接收连接请求,但是处理消息仍然是单线程,不可用于生产
- THsHaServer:THsHaServer继承了TNonblockingServer,不同之处在于THsHaServer内部使用了一个线程池来处理请求。THsHaServer相比较于TNonblockingServer类似TThreadPoolServer相比较于TSimpleServer。另外,当使用TNonblockingServer或者THsHaServer时,必须使用TFramedTransport来封装一下原始的transport
- TThreadedSelectorServer:是thrift 0.8引入的实现,处理请求也使用了线程池,比THsHaServer有更高的吞吐量和更低的时延

京公网安备 11010502036488号