RPC-02-Thrift

聲明:原創(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)
代碼目錄結(jié)構(gòu)
4.5 測試

服務(wù)端:

服務(wù)端

客戶端:

客戶端
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末稚补,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子框喳,更是在濱河造成了極大的恐慌课幕,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件五垮,死亡現(xiàn)場離奇詭異乍惊,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)放仗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進(jìn)店門润绎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人诞挨,你說我怎么就攤上這事莉撇。” “怎么了惶傻?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵棍郎,是天一觀的道長。 經(jīng)常有香客問我达罗,道長坝撑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任粮揉,我火速辦了婚禮,結(jié)果婚禮上抚笔,老公的妹妹穿的比我還像新娘扶认。我一直安慰自己,他們只是感情好殊橙,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布辐宾。 她就那樣靜靜地躺著狱从,像睡著了一般。 火紅的嫁衣襯著肌膚如雪叠纹。 梳的紋絲不亂的頭發(fā)上季研,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天,我揣著相機(jī)與錄音誉察,去河邊找鬼与涡。 笑死,一個胖子當(dāng)著我的面吹牛持偏,可吹牛的內(nèi)容都是我干的驼卖。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼鸿秆,長吁一口氣:“原來是場噩夢啊……” “哼酌畜!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起卿叽,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤桥胞,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后考婴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贩虾,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年蕉扮,在試婚紗的時候發(fā)現(xiàn)自己被綠了整胃。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡喳钟,死狀恐怖屁使,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情奔则,我是刑警寧澤蛮寂,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站易茬,受9級特大地震影響酬蹋,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜抽莱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一范抓、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧食铐,春花似錦匕垫、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽寞秃。三九已至,卻和暖如春偶惠,著一層夾襖步出監(jiān)牢的瞬間春寿,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工忽孽, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留绑改,地道東北人。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓扒腕,卻偏偏與公主長得像绢淀,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子瘾腰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容