Thrift

什么是Thrift

Protobuf是一個語言中立、平臺中立,對結(jié)構(gòu)化數(shù)據(jù)進行序列化的可擴展機制。

我們在開發(fā)的時候開發(fā)了一個restful web service,就是基于rest的http調(diào)用,A系統(tǒng)作為客戶端,B系統(tǒng)作為服務(wù)器端。A系統(tǒng)可以通過URL的方式攜帶一些數(shù)據(jù)去調(diào)用B所提供的接口然后返回相應(yīng)的結(jié)果數(shù)據(jù)。這種方式我們也可以認為是RPC的一種實現(xiàn)方式。對于這種方式我們可以認為是平臺獨立的、語言獨立的,也就是語言中立、平臺中立。也就是我們可以用Python編寫的客戶端去調(diào)用Java編寫的服務(wù)端,因為都是通過URL的方式調(diào)用。因為URL相當(dāng)于契約,URL背后的代碼調(diào)用者無需關(guān)心。

RPC框架調(diào)用基本模型:如person.getPersonByName(String name),首先客戶端先序列化調(diào)用數(shù)據(jù),傳給服務(wù)端,服務(wù)端再反序列化提取調(diào)用信息,查詢客戶端所需要的數(shù)據(jù),完成之后再序列化結(jié)果傳回給客戶端。客戶端再反序列化得到結(jié)果。

Apache thrift是一個可伸縮的,并且跨語言的一種服務(wù)性的開發(fā),他所完成的功能實際上和protobuf是類似的。簡單來說,是Facebook公布的一款開源跨語言的RPC框架。

【什么是RPC框架?】

RPC全稱為Remote Procedure Call,意為遠程過程調(diào)用。

假設(shè)有兩臺服務(wù)器A,B.A服務(wù)器上部署著一個應(yīng)用a,B服務(wù)器上部署著一個應(yīng)用b,現(xiàn)在a希望能夠調(diào)用b應(yīng)用的某個函數(shù)(方法),但是二者不在同一個進程內(nèi),不能直接調(diào)用,就需要通過網(wǎng)絡(luò)傳輸,在AB服務(wù)器之間建一條網(wǎng)絡(luò)傳輸通道,a把參數(shù)傳過去,b接收到參數(shù)調(diào)用自己的方法得到結(jié)果,再通過網(wǎng)絡(luò)傳回給a。

簡單講就是A通過網(wǎng)絡(luò)來調(diào)用B的過程,這個過程要涉及的東西很多,比如多線程、Socket、序列化反序列化、網(wǎng)絡(luò)I/O,很復(fù)雜。于是牛掰的程序員把這些封裝起來做成一套框架供大家使用,就是RPC框架。

【Thrift的跨語言特型】

thrift通過一個中間語言IDL(接口定義語言)來定義RPC的數(shù)據(jù)類型和接口,這些內(nèi)容寫在以.thrift結(jié)尾的文件中,然后通過特殊的編譯器來生成不同語言的代碼,以滿足不同需要的開發(fā)者。比如java開發(fā)者,就可以生成java代碼,c++開發(fā)者可以生成c++代碼,生成的代碼中不但包含目標(biāo)語言的接口定義、方法、數(shù)據(jù)類型,還包含有RPC協(xié)議層和傳輸層的實現(xiàn)代碼。

【Thrift的協(xié)議棧結(jié)構(gòu)】

Thrift是一種c/s的架構(gòu)體系。TServer主要任務(wù)是高效的接受客戶端請求,并將請求轉(zhuǎn)發(fā)給Processor處理。

  • 最上層是用戶自行實現(xiàn)的業(yè)務(wù)邏輯代碼;
  • Processor是由thrift編譯器自動生成的代碼,它封裝了從輸入數(shù)據(jù)流中讀數(shù)據(jù)和向數(shù)據(jù)流中寫數(shù)據(jù)的操作,它的主要工作是:從連接中讀取數(shù)據(jù),把處理交給用戶實現(xiàn)impl,最后把結(jié)果寫到連接上。
  • TProtocol是用于數(shù)據(jù)類型解析的,將結(jié)構(gòu)化數(shù)據(jù)轉(zhuǎn)化為字節(jié)流給TTransport進行傳輸。從TProtocol以下部分是thirft的傳輸協(xié)議和底層I/O通信。
  • TTransport是與底層數(shù)據(jù)傳輸密切相關(guān)的傳輸層,負責(zé)以字節(jié)流方式接收和發(fā)送消息體,不關(guān)注是什么數(shù)據(jù)類型。
  • 底層IO負責(zé)實際的數(shù)據(jù)傳輸,包括socket、文件和壓縮數(shù)據(jù)流等。

進入Thrift大門的第一個java小實例

  1. 創(chuàng)建一個服務(wù)Hello,創(chuàng)建文件Hello.thrift,代碼如下:
namespace java service.demo
service Hello{
    string helloString(1:string para)
}
  1. 終端進入Hello.thrift所在目錄,執(zhí)行命令:
thrift -r -gen java Hello.thrift

發(fā)現(xiàn)在當(dāng)前目錄下多了一個gen-java的目錄,里面的有一個Hello.java的文件。這個java文件包含Hello服務(wù)的接口定義Hello.Iface,以及服務(wù)調(diào)用的底層通信細節(jié),包括客戶端的調(diào)用邏輯Hello.Client以及服務(wù)端的處理邏輯Hello.Processor

  1. 創(chuàng)建一個Maven管理的Java項目,pom.xml中添加相關(guān)的依賴,并將Hello.java文件復(fù)制到項目中:
<dependency>
      <groupId>org.apache.thrift</groupId>
      <artifactId>libthrift</artifactId>
      <version>0.10.0</version>
</dependency>
<dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>1.7.5</version>
</dependency>
  1. 創(chuàng)建HelloServiceImpl實現(xiàn)Hello.Iface接口:
package service.demo;
import org.apache.thrift.TException;

public class HelloServiceImpl implements Hello.Iface {
    public String helloString(String para) throws TException {
        return "result:"+para;
    }
}
  1. 創(chuàng)建服務(wù)端實現(xiàn)代碼HelloServiceServer,把HelloServiceImpl作為一個具體的處理器傳遞給Thrift服務(wù)器:
public class HelloServiceServer {
    /**
     * 啟動thrift服務(wù)器
     */
    public static void main(String[] args) {
        try {
            System.out.println("服務(wù)端開啟....");
            // 1.創(chuàng)建TProcessor
            TProcessor tprocessor = new Hello.Processor<Hello.Iface>(new HelloServiceImpl());
            // 2.創(chuàng)建TserverTransport
            TServerSocket serverTransport = new TServerSocket(9898);
            // 3.創(chuàng)建TProtocol
            TBinaryProtocol.Factory factory = new TBinaryProtocol.Factory();

            TServer.Args tArgs = new TServer.Args(serverTransport);
            tArgs.processor(tprocessor);
            tArgs.protocolFactory(factory);

            // 4.創(chuàng)建Tserver,傳入需要的參數(shù),server將以上內(nèi)容集成在一起
            TServer server = new TSimpleServer(tArgs);
            // 5.啟動server
            server.serve();
        }catch (TTransportException e) {
            e.printStackTrace();
        }
    }
}
  1. 創(chuàng)建客戶端實現(xiàn)代碼HelloServiceClient,調(diào)用Hello.client訪問服務(wù)端的邏輯實現(xiàn):
public class HelloServiceClient {

    public static void main(String[] args) {
        System.out.println("客戶端啟動....");
        TTransport transport = null;
        try {
            transport = new TSocket("localhost", 9898, 30000);
            // 協(xié)議要和服務(wù)端一致
            TProtocol protocol = new TBinaryProtocol(transport);
            Hello.Client client = new Hello.Client(protocol);
            transport.open();
            String result = client.helloString("哈哈");
            System.out.println(result);
        } catch (TTransportException e) {
            e.printStackTrace();
        } catch (TException e) {
            e.printStackTrace();
        } finally {
            if (null != transport) {
                transport.close();
            }
        }
    }
}

全部工作完成后,下面來測試一下,先執(zhí)行服務(wù)端main方法,在執(zhí)行客戶端main方法,會在客戶端控制臺打印出:哈哈

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容