Thrift功能和使用

為什么需要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)

image.png

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


image.png

這個(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)客戶端

image.png

image.png

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

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

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