文章目录
- 1、Thrift RPC介绍
- 1.1、Protocol 支持的数据传输协议
- 1.2、Transport 支持的数据传输方式
- 1.3、Server 支持的服务模型
- 1.4、IDL语法数据类型
- 1.5、开发步骤
- 2、接口定义文件
- 2.1、创建接口定义文件
- 2.2、生成对应平台语言代码
- 2.2.1、下载生成工具
- 2.2.2、生成各平台语言代码
- 3、使用Java实现服务器端
- 4、客户端实现
- 4.1、Java调用客户端实现
- 4.2、Go调用客户端实现
- 4.3、PHP调用客户端实现
1、Thrift RPC介绍
Thrift 是一个软件框架(远程过程调用框架),用来进行可扩展且跨语言的服务的开发,封装了数据传输格式(二进制、json)和网络通信的服务框架,提供多语言(C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml)的网络服务器端和客户端程序组件
适用于搭建大型数据交换及存储的通用工具,对于大型系统中的内部数据传输相对于 JSON 和 xml 无论在性能、传输大小上有明显的优势。
Thrift 开发的几个概念:
Server 服务模型
Handler 数据处理接口
Processor 数据处理对象
Protocol 数据传输协议
Transport 数据传输方式
1.1、Protocol 支持的数据传输协议
- TBinaryProtocol – 二进制格式.
- TCompactProtocol – 压缩格式
- TJSONProtocol – JSON 格式
- TSimpleJSONProtocol –提供 JSON 只写协议,生成的文件很容易通过脚本语言解析。
- TDebugProtocol – 使用易懂的可读的文本格式,以便于 debug
1.2、Transport 支持的数据传输方式
- TFileTransport:文件(日志)传输类,允许 client 将文件传给 server,允许 server 将收到的数据写到文件中。
- THttpTransport:采用 Http 传输协议进行数据传输
- TSocket:采用 TCP Socket 进行数据传输
- TZlibTransport:压缩后对数据进行传输,或者将收到的数据解压
下面几个类主要是对上面几个类地装饰(采用了装饰模式),以提高传输效率。
TBufferedTransport:对某个 Transport 对象操作的数据进行 buffer,即从 buffer 中读取数据进行传输,或者将数据直接写入 buffer
TFramedTransport:以 frame 为单位进行传输,非阻塞式服务中使用。同 TBufferedTransport 类似,也会对相关数据进行 buffer,同时,它支持定长数据发送和接收。
TMemoryBuffer:从一个缓冲区中读写数据
1.3、Server 支持的服务模型
TSimpleServer – 简单的单线程服务模型,常用于测试
TThreadedServer - 多线程服务模型,使用阻塞式 IO,每个请求创建一个线程。
TThreadPoolServer – 线程池服务模型,使用标准的阻塞式 IO,预先创建一组线程处理请求。
TNonblockingServer – 多线程服务模型,使用非阻塞式 IO(需使用 TFramedTransport 数据传输方式)
处理大量更新的话,主要是在 TThreadedServer 和 TNonblockingServer 中进行选择。TNonblockingServer 能够使用少量线程处理大量并发连接,但是延迟较高;TThreadedServer 的延迟较低。实际中,TThreadedServer 的吞吐量可能会比 TNonblockingServer 高,但是 TThreadedServer 的 CPU 占用要比 TNonblockingServer 高很多。
1.4、IDL语法数据类型
- 基本类型
bool:布尔值(true或false)
byte:8位有符号整数
i16:16位有符号整数
i32:32位有符号整数
i64:64位有符号整数
double:64位浮点数
string:使用UTF-8编码编码的文本字符串
- 容器类型
list<t1>:一系列t1类型的元素组成的有序列表,元素可以重复
set<t1>:一些t1类型的元素组成的无序集合,元素唯一不重复
map<t1,t2>:key/value对,key唯一
1.5、开发步骤
服务器端开发:
1. 创建 Handler
2. 基于 Handler 创建 Processor
3. 创建 Transport(通信方式)
4. 创建 Protocol 方式(设定传输格式)
5. 基于 Processor, Transport 和 Protocol 创建 Server
6. 运行 Server
客户端开发:
1. 创建 Transport
2. 创建 Protocol 方式
3. 基于 Transport 和 Protocol 创建 Client
4. 运行 Client 的方法
2、接口定义文件
2.1、创建接口定义文件
test.thrift
/*** The first thing to know about are types. The available types in Thrift are:** bool Boolean, one byte* byte Signed byte* i16 Signed 16-bit integer* i32 Signed 32-bit integer* i64 Signed 64-bit integer* double 64-bit floating point value* string String* binary Blob (byte array)* map<t1,t2> Map from one type to another* list<t1> Ordered list of one type* set<t1> Set of unique elements of one type** Did you also notice that Thrift supports C style comments?*/// 命名空间,Java中的package
namespace java com.penngo.thrift
namespace php com.penngo
namespace go com.penngo// 结构体
struct User {1: i64 id,2: string name,3: string password
}// 服务,Java中创建Interface一样
service LoginService{// service中定义的函数,相当于Java interface中定义的函数User login(1:string name, 2:string psw);
}service RegisterService{User createUser(1:string name, 2:string psw);
}
2.2、生成对应平台语言代码
2.2.1、下载生成工具
下载地址:https://thrift.apache.org/download
当前最新版本为:thrift-0.19.0.exe
thrift-0.19.0.exe重命名为thrift.exe,与test.thrift在同一目录。
2.2.2、生成各平台语言代码
执行以下命令分别生成Java、Go、PHP平台的代码
thrift -gen java test.thrift
thrift -gen go test.thrift
thrift -gen php:classmap test.thrift # 支持PSR-4 loader
# thrift -gen php test.thrift
生成后的目录文件结构
3、使用Java实现服务器端
pom.xml
<?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>com.penngo</groupId><artifactId>thrift-java</artifactId><version>1.0</version><properties><maven.compiler.source>11</maven.compiler.source><maven.compiler.target>11</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>org.apache.thrift</groupId><artifactId>libthrift</artifactId><version>0.19.0</version></dependency><dependency><groupId>javax.annotation</groupId><artifactId>javax.annotation-api</artifactId><version>1.3.2</version></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>2.17.2</version></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.17.2</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-simple</artifactId><version>1.7.36</version></dependency></dependencies><repositories><repository><id>alimaven</id><name>Maven Aliyun Mirror</name><url>https://maven.aliyun.com/repository/central</url></repository></repositories><pluginRepositories><pluginRepository><id>public</id><name>aliyun nexus</name><url>https://maven.aliyun.com/nexus/content/groups/public/</url><releases><enabled>true</enabled></releases><snapshots><enabled>false</enabled></snapshots></pluginRepository></pluginRepositories>
</project>
实现LoginService服务LoginServiceImpl.java
package com.penngo.service;import com.penngo.thrift.LoginService;
import com.penngo.thrift.User;public class LoginServiceImpl implements LoginService.Iface{public LoginServiceImpl(){}public User login(String name, String psw){User user = null;if(name.equals("penngo") && psw.equals("123")){user = new User();user.setId(1);user.setName("penngo");}return user;}
}
实现RegisterService服务RegisterServiceImpl.java
package com.penngo.service;
import com.penngo.thrift.RegisterService;
import com.penngo.thrift.User;public class RegisterServiceImpl implements RegisterService.Iface{public RegisterServiceImpl(){}public User createUser(String name, String psw){User user = new User();user.setId(2);user.setName(name);user.setPassword(psw);return user;}
}
实现LoginService和RegisterService注册,完成服务启动。
package com.penngo;import com.penngo.service.LoginServiceImpl;
import com.penngo.service.RegisterServiceImpl;
import com.penngo.thrift.LoginService;
import com.penngo.thrift.RegisterService;
import org.apache.thrift.TMultiplexedProcessor;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TThreadPoolServer;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TTransportException;public class HelloServer {private void start() {try {TServerSocket serverTransport = new TServerSocket(7911);// 用户登录LoginService.Processor loginProcessor = new LoginService.Processor(new LoginServiceImpl());// 用户注册RegisterService.Processor registerProcessor = new RegisterService.Processor(new RegisterServiceImpl());TMultiplexedProcessor processor = new TMultiplexedProcessor();processor.registerProcessor("LoginService", loginProcessor);processor.registerProcessor("RegisterService", registerProcessor);TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(serverTransport).processor(processor));System.out.println("Starting server on port 7911 ...");server.serve();} catch (TTransportException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();}}public static void main(String args[]) {HelloServer srv = new HelloServer();srv.start();}
}
项目文件结构
4、客户端实现
4.1、Java调用客户端实现
package com.penngo;import com.penngo.thrift.LoginService;
import com.penngo.thrift.RegisterService;
import com.penngo.thrift.User;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TMultiplexedProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;public class HelloClient {public static void main(String[] args) {try {TTransport transport = new TSocket("localhost", 7911);TProtocol protocol = new TBinaryProtocol(transport);TMultiplexedProtocol mp1 = new TMultiplexedProtocol(protocol,"LoginService");LoginService.Client loginClient = new LoginService.Client(mp1);TMultiplexedProtocol mp2 = new TMultiplexedProtocol(protocol,"RegisterService");RegisterService.Client registerClient = new RegisterService.Client(mp2);transport.open();User user = loginClient.login("penngo", "123");if (user != null) {System.out.println("登录成功:" + user.getId() + " "+ user.getName());} else {System.out.println("登录失败");}User user2 = registerClient.createUser("test", "123456");if (user2 != null) {System.out.println("创建用户成功:" + user2.getId() + " "+ user2.getName());} else {System.out.println("创建用户失败");}transport.close();} catch (TException x) {x.printStackTrace();}}
}
4.2、Go调用客户端实现
安装Thrift依赖
go get github.com/apache/thrift
go客户端实现
package mainimport ("context""crypto/tls""fmt""github.com/apache/thrift/lib/go/thrift""net""os""thrifttest/com/penngo"
)const (HOST = "127.0.0.1"PORT = "7911"
)var ctx = context.Background()func main() {cfg := &thrift.TConfiguration{TLSConfig: &tls.Config{InsecureSkipVerify: true,}}// 网络接口var transport thrift.TTransportvar err errortransport = thrift.NewTSocketConf(net.JoinHostPort(HOST, PORT), cfg)protocol := thrift.NewTBinaryProtocolConf(transport, cfg)// 客户端iprot := thrift.NewTMultiplexedProtocol(protocol, "LoginService")oprot := thrift.NewTMultiplexedProtocol(protocol, "LoginService")c := thrift.NewTStandardClient(iprot, oprot)loginClient := penngo.NewLoginServiceClient(c)// 客户端iprot2 := thrift.NewTMultiplexedProtocol(protocol, "RegisterService")oprot2 := thrift.NewTMultiplexedProtocol(protocol, "RegisterService")c2 := thrift.NewTStandardClient(iprot2, oprot2)registerClient := penngo.NewRegisterServiceClient(c2)if err := transport.Open(); err != nil {fmt.Fprintln(os.Stderr, "open transport error: ", err)os.Exit(1)}defer transport.Close()res, err := loginClient.Login(ctx, "penngo", "123")if err != nil {fmt.Fprintln(os.Stderr, "======error: ", err)os.Exit(1)}fmt.Fprintln(os.Stderr, "Login=====: ", res)res2, err2 := registerClient.CreateUser(ctx, "test", "123456")if err2 != nil {fmt.Fprintln(os.Stderr, "======error: ", err2)os.Exit(1)}fmt.Fprintln(os.Stderr, "CreateUser=====: ", res2)
}
项目文件结构
官方例子:https://thrift.apache.org/tutorial/go.html
4.3、PHP调用客户端实现
创建composer.json
{"require": {"apache/thrift": "^0.19.0"},"autoload": {"files": ["com/penngo/LoginService.php","com/penngo/RegisterService.php","com/penngo/Types.php"]}
}
使用composer安装依赖
composer install
php客户端实现代码
<?php
require_once 'vendor/autoload.php';use Thrift\Transport\TSocket;
use Thrift\Protocol\TBinaryProtocol;
use Thrift\Transport\TBufferedTransport;
use Thrift\Protocol\TMultiplexedProtocol;
use com\penngo\LoginServiceClient;
use com\penngo\RegisterServiceClient;// 传输方式(需与服务端一致)
$socket = new TSocket("localhost", 7911);
// 传输协议(需与服务端一致)
$transport = new TBufferedTransport($socket, 1024, 1024);
$protocol = new TBinaryProtocol($transport);
$loginProtocol = new TMultiplexedProtocol($protocol, "LoginService");
$registerProtocol = new TMultiplexedProtocol($protocol, "RegisterService");
$loginClient = new LoginServiceClient($loginProtocol);
$registerClient = new RegisterServiceClient($registerProtocol);
$transport->open();
$user = $loginClient->login('penngo', '123');
print "login====".json_encode($user);$user = $registerClient->createUser('test', '123456');
print "\ncreateUser====".json_encode($user);
$transport->close();
项目文件结构
php官方例子:https://thrift.apache.org/lib/php.html
附件源码