聲明:原創(chuàng)文章,轉(zhuǎn)載請注明出處贱枣。http://www.reibang.com/u/e02df63eaa87
1坐搔、概述
Thrift是一個軟件框架何恶,用來進(jìn)行可擴(kuò)展且跨語言的服務(wù)的開發(fā)捌议。它結(jié)合了功能強(qiáng)大的軟件堆棧和代碼生成引擎哼拔,以構(gòu)建在 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 等等編程語言間無縫結(jié)合的、高效的服務(wù)瓣颅。
Thrift最初由facebook開發(fā)倦逐,07年四月開放源碼,08年5月進(jìn)入apache孵化器弄捕。thrift允許你定義一個簡單的定義文件中的數(shù)據(jù)類型和服務(wù)接口僻孝。以作為輸入文件,編譯器生成代碼用來方便地生成RPC客戶端和服務(wù)器通信的無縫跨編程語言守谓。其傳輸數(shù)據(jù)采用二進(jìn)制格式,相對于XML和JSON等序列化方式體積更小您单,對于高并發(fā)斋荞、大數(shù)據(jù)量和多語言的環(huán)境更有優(yōu)勢。
Thrift它含有三個主要的組件:protocol虐秦,transport和server平酿,其中,protocol定義了消息是怎樣序列化的悦陋,transport定義了消息是怎樣在客戶端和服務(wù)器端之間通信的蜈彼,server用于從transport接收序列化的消息,根據(jù)protocol反序列化之俺驶,調(diào)用用戶定義的消息處理器幸逆,并序列化消息處理器的響應(yīng),然后再將它們寫回transport。
官網(wǎng)地址:thrift.apache.org
推薦值得一看的文章:
http://jnb.ociweb.com/jnb/jnbJun2009.html
http://wiki.apache.org/thrift
http://thrift.apache.org/static/files/thrift-20070401.pdf
本文代碼可參考:https://github.com/hawkingfoo/thrift-demo
2还绘、下載配置
到官網(wǎng)下載最新版本楚昭,截止到(2015-12-12)最新版本為0.9.3.
如果是Maven構(gòu)建項(xiàng)目的,直接在pom.xml 中添加如下內(nèi)容:
<!-- https://mvnrepository.com/artifact/org.apache.thrift/libthrift -->
<dependency>
<groupId>org.apache.thrift</groupId>
<artifactId>libthrift</artifactId>
<version>0.9.3</version>
</dependency>
3拍顷、基本概念
3.1 數(shù)據(jù)類型
基本類型:
bool:布爾值抚太,true 或 false,對應(yīng) Java 的 boolean
byte:8 位有符號整數(shù)昔案,對應(yīng) Java 的 byte
i16:16 位有符號整數(shù)尿贫,對應(yīng) Java 的 short
i32:32 位有符號整數(shù),對應(yīng) Java 的 int
i64:64 位有符號整數(shù)踏揣,對應(yīng) Java 的 long
double:64 位浮點(diǎn)數(shù)帅霜,對應(yīng) Java 的 double
string:未知編碼文本或二進(jìn)制字符串,對應(yīng) Java 的 String
結(jié)構(gòu)體類型:
struct:定義公共的對象呼伸,類似于 C 語言中的結(jié)構(gòu)體定義身冀,在 Java 中是一個 JavaBean
集合類型:
list:對應(yīng) Java 的 ArrayList
set:對應(yīng) Java 的 HashSet
map:對應(yīng) Java 的 HashMap
異常類型:
exception:對應(yīng) Java 的 Exception
服務(wù)類型:
service:對應(yīng)服務(wù)的類
3.2 數(shù)據(jù)傳輸層Transport
- TSocket —— 使用阻塞式 I/O 進(jìn)行傳輸,是最常見的模式
- TFramedTransport —— 使用非阻塞方式括享,按塊的大小進(jìn)行傳輸搂根,類似于 Java 中的 NIO,若使用 TFramedTransport 傳輸層铃辖,其服務(wù)器必須修改為非阻塞的服務(wù)類型
- TNonblockingTransport —— 使用非阻塞方式剩愧,用于構(gòu)建異步客戶端
3.3 數(shù)據(jù)傳輸協(xié)議Protocol
Thrift 可以讓用戶選擇客戶端與服務(wù)端之間傳輸通信協(xié)議的類別,在傳輸協(xié)議上總體劃分為文本 (text) 和二進(jìn)制 (binary) 傳輸協(xié)議娇斩,為節(jié)約帶寬仁卷,提高傳輸效率,一般情況下使用二進(jìn)制類型的傳輸協(xié)議為多數(shù)犬第,有時還會使用基于文本類型的協(xié)議锦积,這需要根據(jù)項(xiàng)目 / 產(chǎn)品中的實(shí)際需求。常用協(xié)議有以下幾種:
- TBinaryProtocol —— 二進(jìn)制編碼格式進(jìn)行數(shù)據(jù)傳輸
TProtocol protocol = new TBinaryProtocol(transport);
- TCompactProtocol —— 高效率的歉嗓、密集的二進(jìn)制編碼格式進(jìn)行數(shù)據(jù)傳輸
TCompactProtocol protocol = new TCompactProtocol(transport);
- TJSONProtocol —— 使用 JSON 的數(shù)據(jù)編碼協(xié)議進(jìn)行數(shù)據(jù)傳輸
TJSONProtocol protocol = new TJSONProtocol(transport);
- TSimpleJSONProtocol —— 只提供 JSON 只寫的協(xié)議丰介,適用于通過腳本語言解析**
TProtocol protocol = new TSimpleJSONProtocol(transport);
3.4 服務(wù)器類型Server
- TSimpleServer —— 單線程服務(wù)器端使用標(biāo)準(zhǔn)的阻塞式 I/O,一般用于測試鉴分。
- TThreadPoolServer —— 多線程服務(wù)器端使用標(biāo)準(zhǔn)的阻塞式 I/O哮幢,預(yù)先創(chuàng)建一組線程處理請求。
- TNonblockingServer —— 多線程服務(wù)器端使用非阻塞式 I/O志珍,服務(wù)端和客戶端需要指定 TFramedTransport 數(shù)據(jù)傳輸?shù)姆绞健?/li>
- THsHaServer —— 半同步半異步的服務(wù)端模型橙垢,需要指定為: TFramedTransport 數(shù)據(jù)傳輸?shù)姆绞健K褂靡粋€單獨(dú)的線程來處理網(wǎng)絡(luò)I/O伦糯,一個獨(dú)立的worker線程池來處理消息柜某。這樣嗽元,只要有空閑的worker線程,消息就會被立即處理莺琳,因此多條消息能被并行處理还棱。
- TThreadedSelectorServer —— TThreadedSelectorServer允許你用多個線程來處理網(wǎng)絡(luò)I/O。它維護(hù)了兩個線程池惭等,一個用來處理網(wǎng)絡(luò)I/O珍手,另一個用來進(jìn)行請求的處理。當(dāng)網(wǎng)絡(luò)I/O是瓶頸的時候辞做,TThreadedSelectorServer比THsHaServer的表現(xiàn)要好琳要。
4、實(shí)例
4.1 準(zhǔn)備
新建Maven項(xiàng)目秤茅,并且添加thrift依賴
<dependencies>
<dependency>
<groupId>org.apache.thrift</groupId>
<artifactId>libthrift</artifactId>
<version>0.9.3</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.7</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.7</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
4.2 編寫IDL接口并生成接口文件
namespace java thrifttest.service
// 計算類型 - 僅限整數(shù)四則運(yùn)算
enum ComputeType {
ADD = 0;
SUB = 1;
MUL = 2;
DIV = 3;
}
// 服務(wù)請求
struct ComputeRequest {
1:required i64 x;
2:required i64 y;
3:required ComputeType computeType;
}
// 服務(wù)響應(yīng)
struct ComputeResponse {
1:required i32 errorNo;
2:optional string errorMsg;
3:required i64 computeRet;
}
service ComputeServer {
ComputeResponse getComputeResult(1:ComputeRequest request);
}
執(zhí)行編譯命令:
thrift-0.9.3.exe --gen java computeServer.thrift
4.3 服務(wù)端接口實(shí)現(xiàn)以及服務(wù)啟動
public class ThriftTestImpl implements ComputeServer.Iface {
private static final Logger logger = LogManager.getLogger(ThriftTestImpl.class);
public ComputeResponse getComputeResult(ComputeRequest request) {
ComputeType computeType = request.getComputeType();
long x = request.getX();
long y = request.getY();
logger.info("get compute result begin. [x:{}] [y:{}] [type:{}]", x, y, computeType.toString());
long begin = System.currentTimeMillis();
ComputeResponse response = new ComputeResponse();
response.setErrorNo(0);
try {
long ret;
if (computeType == ComputeType.ADD) {
ret = add(x, y);
response.setComputeRet(ret);
} else if (computeType == ComputeType.SUB) {
ret = sub(x, y);
response.setComputeRet(ret);
} else if (computeType == ComputeType.MUL) {
ret = mul(x, y);
response.setComputeRet(ret);
} else {
ret = div(x, y);
response.setComputeRet(ret);
}
} catch (Exception e) {
response.setErrorNo(1001);
response.setErrorMsg(e.getMessage());
logger.error("exception:", e);
}
long end = System.currentTimeMillis();
logger.info("get compute result end. [errno:{}] cost:[{}ms]",
response.getErrorNo(), (end - begin));
return response;
}
public long add(long x, long y) {
return x + y;
}
public long sub(long x, long y) {
return x - y;
}
public long mul(long x, long y) {
return x * y;
}
public long div(long x, long y) {
return x / y;
}
}
public class ServerMain {
private static final Logger logger = LogManager.getLogger(ServerMain.class);
public static void main(String[] args) {
try {
ThriftTestImpl workImpl = new ThriftTestImpl();
TProcessor tProcessor = new ComputeServer.Processor<ComputeServer.Iface>(workImpl);
final TNonblockingServerTransport transport = new TNonblockingServerSocket(9000);
TThreadedSelectorServer.Args ttpsArgs = new TThreadedSelectorServer.Args(transport);
ttpsArgs.transportFactory(new TFramedTransport.Factory());
ttpsArgs.protocolFactory(new TBinaryProtocol.Factory());
ttpsArgs.processor(tProcessor);
ttpsArgs.selectorThreads(16);
ttpsArgs.workerThreads(32);
logger.info("compute service server on port :" + 9000);
TServer server = new TThreadedSelectorServer(ttpsArgs);
server.serve();
} catch (Exception e) {
logger.error(e);
}
}
}
4.4 客戶端訪問
public class ComputeClient {
private ComputeRequest request;
public ComputeClient() {
request = new ComputeRequest();
request.setX(1);
request.setY(2);
request.setComputeType(ComputeType.ADD);
}
public static void main(String[] args) {
TTransport transport = null;
try {
System.out.println("***********");
long begin = System.currentTimeMillis();
// localhost
transport = new TFramedTransport(new TSocket("127.0.0.1", 9000));
transport.open();
TProtocol protocol = new TBinaryProtocol(transport);
ComputeServer.Client client = new ComputeServer.Client(protocol);
//調(diào)用client的getComputeResult方法
ComputeResponse response = client.getComputeResult(new ComputeClient().request);
System.out.println("cost:[" + (System.currentTimeMillis() - begin) + "ms]");
System.out.println("***********");
if (response != null) {
System.out.println(response.toString());
}
transport.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (transport != null)
transport.close();
}
}
}
4.5 整體代碼結(jié)構(gòu)
4.5 測試
服務(wù)端:
客戶端: