為什么需要Thrift
目前程序開發(fā)的模式一般為前后端分離和微服務(wù)模式,前端(如nodejs)對(duì)數(shù)據(jù)處理后傳遞到后端,微服務(wù)模式下多個(gè)模塊之間需要進(jìn)行數(shù)據(jù)的交互。我們?nèi)绾芜M(jìn)行更好更快的數(shù)據(jù)交互呢,目前有主要有兩種方式,一種是通過(guò)HTTP REST的方式,還有一種就是RPC的方式,Thrift就是屬于rpc通信的一種方式。
首先說(shuō)下REST和Thrift的區(qū)別
REST是在HTTP基礎(chǔ)上建立的數(shù)據(jù)交互,數(shù)據(jù)一般采用JSON格式
Thrift是在Socket基礎(chǔ)上進(jìn)行數(shù)據(jù)交互,數(shù)據(jù)傳輸方式靈活,可以通過(guò)二進(jìn)制的方式傳遞,Thrift提供序列化和反序列化,也可以使用JSON格式
thrift存在的問(wèn)題
client端是非線程安全的,如果多個(gè)客戶端使用同一個(gè)socket,就會(huì)出現(xiàn)服務(wù)端錯(cuò)誤,所以需要保證socket單線程使用
使用方式
編寫thrift文件,通過(guò)該文件生成客戶端和服務(wù)的的接口文件,分別在server和client實(shí)現(xiàn)接口文件中的方法,然后就可以直接調(diào)用遠(yuǎn)程服務(wù)了。下面對(duì)這個(gè)概念分別解釋
thrift文件
thrift文件是用來(lái)生成客戶端和服務(wù)端接口的文件,通過(guò)一條簡(jiǎn)單的命令就可以生成:
thrift -r --gen <language> <thrift文件>
thrift語(yǔ)法
基本類型
bool:布爾值 對(duì)應(yīng) java boolean
byte:有符號(hào)字節(jié) 對(duì)應(yīng) java byte
i16:16位有符號(hào)整型 對(duì)應(yīng) java short
i32:32位有符號(hào)整型 對(duì)應(yīng) java int
i64:64位有符號(hào)整型 對(duì)應(yīng) java long
double:64位浮點(diǎn)型 對(duì)應(yīng) java double
string:字符串 對(duì)應(yīng) java String
List<T>:對(duì)應(yīng) java List<T>
Set<T>: 對(duì)應(yīng) java Set<T>
Map<key,value>: 對(duì)應(yīng)java Map<k,v>
結(jié)構(gòu)體
類似于c/c++中的結(jié)構(gòu)體,在結(jié)構(gòu)體中聲明類型,不可以有方法
struct Name{
1:i32 number=10,
2:i64 bigNumber,
3:double decimals,
4:string name="thrifty"
}
結(jié)構(gòu)體中的字段required optional
required字段必須填寫
optional字段沒有賦值則不會(huì)被傳輸,設(shè)置_isset為true后才能傳輸不被丟失
異常
和結(jié)構(gòu)體類似,只是關(guān)鍵字使用exception
枚舉
enum <typename> {
<name>
<name>=value
}
服務(wù)
類似java中的接口,具體方法由clinet/server去實(shí)現(xiàn)
service <name> {
<returntype> <name>(<arguments>)
<returntype> <name>(<arguments>) [throws (<exceptions>)]
}
生成client/server接口
有了thrift文件之后,就可以通過(guò)一條命令直接生成client/server接口了
thrift -r --gen <language> <thrift filename>
最后將生成的文件引入到client/server代碼中,進(jìn)行接口實(shí)現(xiàn),就可以在client進(jìn)行調(diào)用了
下面為完整的生成java代碼并進(jìn)行調(diào)用的demo
1 首先需要定義一個(gè)thrift文件,里面寫上client想要調(diào)用server端的方法
hello.thrift
service hello{
string sayHello()
}
2 生成client/server接口文件
thrift --gen java hello.thrift
在gen-java目錄下得到hello.java文件
3 在項(xiàng)目中引入接口文件,并對(duì)方法進(jìn)行實(shí)現(xiàn)

server端將生成的hello.java引入項(xiàng)目中,并將hello.Iface接口進(jìn)行實(shí)現(xiàn)

這個(gè)方法就是我們?cè)趖hrift中定義的接口方法,由server端進(jìn)行具體的實(shí)現(xiàn)
4 服務(wù)端調(diào)用thrift中的方法對(duì)某一端口進(jìn)行監(jiān)控
package thriftServer;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TThreadPoolServer;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TServerTransport;
import org.apache.thrift.transport.TTransportFactory;
import thriftInterface.hello;
import thriftService.helloImp;
public class GenServer {
private void startServer(){
hello.Processor processor = new hello.Processor<hello.Iface>(new helloImp());
try{
TServerTransport transport = new TServerSocket(1234);
TThreadPoolServer.Args args = new TThreadPoolServer.Args(transport);
args.processor(processor);
args.protocolFactory(new TBinaryProtocol.Factory());
args.transportFactory(new TTransportFactory());
args.minWorkerThreads(10);
args.maxWorkerThreads(20);
TServer server = new TThreadPoolServer(args);
server.serve();
}catch (Exception e){
System.out.println(e);
}
}
public static void main(String[] args) {
GenServer server = new GenServer();
server.startServer();
}
}
5 客戶端通過(guò)Client調(diào)用該方法即可
package thriftClient;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.*;
import thriftInterface.hello;
public class DemoClient {
private static final String SERVER_IP = "localhost";
private static final int SERVER_PORT = 1234;
private static final int TIMEOUT = 1000;
private void startClient(String userName) {
TTransport transport = null;
try {
transport = new TSocket(SERVER_IP, SERVER_PORT, TIMEOUT);
TProtocol protocol = new TBinaryProtocol(transport);
hello.Client client = new hello.Client(protocol);
transport.open();
// 調(diào)用服務(wù)端的方法
String res = client.sayHello();
System.out.println("調(diào)用返回結(jié)果為:" + res);
} catch (TTransportException e) {
e.printStackTrace();
} catch (TException e) {
e.printStackTrace();
} finally {
if (null != transport) {
transport.close();
}
}
}
public static void main(String[] args) {
DemoClient client = new DemoClient();
client.startClient("hello");
}
}
6 執(zhí)行結(jié)果
啟動(dòng)服務(wù)端,再啟動(dòng)客戶端


至此,完整的client/server調(diào)用就完成了
另,maven依賴如下:
<dependencies>
<dependency>
<groupId>org.apache.thrift</groupId>
<artifactId>libthrift</artifactId>
<version>0.13.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
</dependencies>
