跨語言RPC框架Thrift詳解

一、 概念
Apache的Thrift軟件框架,是用來進行可伸縮的、跨語言的服務開發,它通過一個代碼生成引擎來構建高效、無縫的服務,這些服務能夠實現跨語言調度,目前支持的語言有: C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, OCaml and Delphi 等。
二、 安裝Thrift
目前官網最新的版本是v0.10.0。下面主要介紹基于mac os系統的Thrift的安裝。windows系統可參考官網教程進行安裝。

mac os官網提供的安裝方法比較復雜,這里介紹下mac 下的home brew的安裝方法。

打開終端,如果你的mac還沒有安裝home brew,那么先要安裝home brew,使用以下命令:

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

然后安裝最新版本的Thrift:

brew install thrift

然后安裝最新版本的Thrift:

brew install thrift

等待安裝完成,然后輸入以下命令,如果打印了Thrift的版本信息,表示安裝成功:

thrift -version

三、 Thrift支持的類型

  1. 基本類型
    bool:布爾值(true或者false)
    byte:8位的有符號字節(java的byte類型)
    i16:16位的有符號整數(java的short類型)
    i32:32位的有符號整數(java的int類型)
    i64:64位的有符號長整型(java的long類型)
    double:一個64位的浮點數(java的double類型)
    string: 一個utf8編碼的字符串文本(java的String)

  2. Structs
    Thrift的structs用來定義一個通用對象,但是沒有繼承關系。

  3. 集合類型
    list:一個有序的元素列表。元素可以重復。
    set:一個無序的元素集合,集合中元素不能重復。
    map:一個鍵值對的數據結構,相當于Java中的HashMap。

  4. 異常類型Exceptions
    Thrift的異常類型,除了是繼承于靜態異常基類以外,其他的跟struct是類似的。表示的是一個異常對象。

  5. 服務類型Services
    Thrift 的service類型相當于定義一個面向對象編程的一個接口。Thrift的編譯器會根據這個接口定義來生成服務端和客戶端的接口實現代碼。

四、一個簡單的Thrift調用實例

  1. 編寫.thrift文件,也就是IDL(接口描述語言)文件
    以下是data.thrift文件:
namespace java thrift.generated
namespace py py.thrift.generatedtypedef i16 short
typedef i32 int
typedef i64 long
typedef bool boolean
typedef string Stringstruct Person {1: optional String username,2: optional int age,3: optional boolean married
}exception DataException {1: optional String message,2: optional String callStack,3: optional String date
}service PersonService {Person getPersonByUsername(1: required String username) throws (1: DataException dataException),void savePerson(1: required Person person) throws (1: DataException dataException)
}
  1. 使用thrift的編譯器,生成客戶端和服務端的代碼
    生成java的客戶端服務端代碼:
thrift --gen java src/thrift/data.thrift

生成Python的客戶端服務端代碼:

thrift --gen py src/thrift/data.thrift

其他語言的生成也是類似。

  1. Thrift的調用
    以java作為服務端,java作為客戶端以及Python作為客戶端對服務端進行請求。
    java服務端代碼:
public class PersonServiceImpl implements PersonService.Iface {@Overridepublic Person getPersonByUsername(String username) throws DataException, TException {System.out.println("Got client param: " + username);Person person = new Person();person.setUsername(username);person.setAge(20);person.setMarried(false);return person;}@Overridepublic void savePerson(Person person) throws DataException, TException {System.out.println("Got client param: ");System.out.println(person.getUsername());System.out.println(person.getAge());System.out.println(person.isMarried());}
}

java客戶端代碼:

public class ThriftClient {public static void main(String[] args) {TTransport transport = new TFramedTransport(new TSocket("localhost", 8899), 600);TProtocol protocol = new TCompactProtocol(transport);PersonService.Client client = new PersonService.Client(protocol);try {transport.open();Person person = client.getPersonByUsername("張三");System.out.println(person.getUsername());System.out.println(person.getAge());System.out.println(person.isMarried());System.out.println("------------");Person person1 = new Person();person1.setUsername("李四");person1.setAge(30);person1.setMarried(true);client.savePerson(person1);} catch (Exception e) {throw new RuntimeException(e.getMessage(), e);} finally {transport.close();}}}

python客戶端代碼:

__author__ = '作者'from py.thrift.generated import PersonService
from py.thrift.generated import ttypesfrom thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TCompactProtocolimport sysreload(sys)
sys.setdefaultencoding('utf8')try:tSocket = TSocket.TSocket('localhost', 8899)tSocket.setTimeout(600)transport = TTransport.TFramedTransport(tSocket)protocol = TCompactProtocol.TCompactProtocol(transport)client = PersonService.Client(protocol)transport.open()person = client.getPersonByUsername('張三')print person.usernameprint person.ageprint person.marriedprint '------------------'newPerson = ttypes.Person()newPerson.username = '李四'newPerson.age = 30newPerson.married = Trueclient.savePerson(newPerson)except Thrift.TException, tx:print '%s' % tx.message

先運行服務端,然后再運行客戶端,觀察服務端和客戶端的輸出來理解下thrift的一個調用流程是什么樣的。

五、Thrift的架構原理
以下是thrift的客戶端和服務端交互的一個原理圖:
在這里插入圖片描述
如上圖,客戶端在進行遠程方法調用時,首先是通過Thrift的編譯器生成的客戶端,將調用信息(方法名,參數信息)以指定的協議進行封裝,而傳輸層TTransport是對協議層的封裝進行處理(比如封裝成幀frame),并通過網絡發送出去。服務端這邊流程跟客戶端相反,收到客戶端發過來的數據后,首先經過傳輸層對傳過來的數據進行處理,然后使用特定的協議(跟客戶端是一一對應的)進行解析,然后再通過生成的Processor調用用戶編寫的代碼,如果有返回值的話,返回值以逆向的順序,即通過協議層封裝,然后傳輸層處理對數據進行發送,到了客戶端那邊就是對服務端返回的數據進行處理,使用特定協議進行解析,然后得到一個調用個的結果。

以上就是Thrift的RPC調用的一個完整流程。

六、 Thrift的傳輸格式(協議層)
Thrift之所以被稱為一種高效的RPC框架,其中一個重要的原因就是它提供了高效的數據傳輸。
以下是Thrift的傳輸格式種類:

TBinaryProtocol: 二進制格式。效率顯然高于文本格式。
TCompactProtocol:壓縮格式。在二進制基礎上進一步壓縮。
TJSONProtocol:JSON格式。
TSimpleJSONProtocol:提供JSON只寫協議(缺少元數據信息),生成的文件很容易用過腳本語言解析。
TDebugProtocol:使用易懂的刻度文本格式,以便于調試。
以上可以看到,在線上環境,使用TCompactProtocol格式效率是最高的,同等數據傳輸占用網絡帶寬是最少的。

七、Thrift的數據傳輸方式(傳輸層)
TSocket:阻塞式socket。
TFramedTransport:以frame為單位進行傳輸,非阻塞式服務中使用。
TFileTransport:以文件形式進行傳輸。
TMemoryTransport:將內存用于I/O,Java是現實內部實際使用了簡單的ByteArrayOutputStream。
TZlibTransport:使用zlib進行壓縮,與其他傳輸方式聯合使用。當前無java實現。
八、Thrift的服務模型
TSimpleServer
簡單的單線程服務模型,常用于測試。只在一個單獨的線程中以阻塞I/O的方式來提供服務。所以它只能服務一個客戶端連接,其他所有客戶端在被服務器端接受之前都只能等待。
TNonblockingServer
它使用了非阻塞式I/O,使用了java.nio.channels.Selector,通過調用select(),它使得程序阻塞在多個連接上,而不是單一的一個連接上。TNonblockingServer處理這些連接的時候,要么接受它,要么從它那讀數據,要么把數據寫到它那里,然后再次調用select()來等待下一個準備好的可用的連接。通用這種方式,server可同時服務多個客戶端,而不會出現一個客戶端把其他客戶端全部“餓死”的情況。缺點是所有消息是被調用select()方法的同一個線程處理的,服務端同一時間只會處理一個消息,并沒有實現并行處理。
THsHaServer(半同步半異步server)
針對TNonblockingServer存在的問題,THsHaServer應運而生。它使用一個單獨的線程專門負責I/O,同樣使用java.nio.channels.Selector,通過調用select()。然后再利用一個獨立的worker線程池來處理消息。只要有空閑的worker線程,消息就會被立即處理,因此多條消息能被并行處理。效率進一步得到了提高。
TThreadedSelectorServer
它與THsHaServer的主要區別在于,TThreadedSelectorServer允許你用多個線程來處理網絡I/O。它維護了兩個線程池,一個用來處理網絡I/O,另一個用來進行請求的處理。
TThreadPoolServer
它使用的是一種多線程服務模型,使用標準的阻塞式I/O。它會使用一個單獨的線程來接收連接。一旦接受了一個連接,它就會被放入ThreadPoolExecutor中的一個worker線程里處理。worker線程被綁定到特定的客戶端連接上,直到它關閉。一旦連接關閉,該worker線程就又回到了線程池中。
這意味著,如果有1萬個并發的客戶端連接,你就需要運行1萬個線程。所以它對系統資源的消耗不像其他類型的server一樣那么“友好”。此外,如果客戶端數量超過了線程池中的最大線程數,在有一個worker線程可用之前,請求將被一直阻塞在那里。
如果提前知道了將要連接到服務器上的客戶端數量,并且不介意運行大量線程的話,TThreadPoolServer可能是個很好的選擇。
九、 其他
Facebook開源了一個簡化thrift java開發的一個庫——swift。swift是一個易于使用的、基于注解的java庫,主要用來創建thrift可序列化類型和服務。

github地址:https://github.com/facebook/swift

十、 總結
Thrift是一個跨語言的RPC框架,如果有跨語言交互的業務場景,Thrift可能是一個很好的選擇。如果使用恰當,thrift將是一個非常高效的一個RPC框架。開發時應根據具體場景選擇合適的協議,傳輸方式以及服務模型。缺點就是Thrift并沒有像dubbo那樣提供分布式服務的支持,如果要支持分布式,需要開發者自己去開發集成。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/249743.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/249743.shtml
英文地址,請注明出處:http://en.pswp.cn/news/249743.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

小知識

1.時間格式的處理 new Date().format(yyyy-MM-dd hh:mm:ss) 2.保留兩位小數的方法 element.recTime element.recTime.toFixed(2) 3.如何判斷一個對象為空的方法 JSON.stringify(this.getEcho) ! "{}" 4.判斷時間是否為標準格式的方法 (this.formValidate.outDateti…

增加標 和增加其內容

create table student( sno varchar(20) not null comment學號, sname varchar(20) not null comment學生姓名, ssex varchar(20) not null comment學生性別, sbirthday datetime comment學生出生年月, class varchar(20) comment 學生所在班級, primary key…

RPC服務和HTTP服務對比

很長時間以來都沒有怎么好好搞清楚RPC(即Remote Procedure Call,遠程過程調用)和HTTP調用的區別,不都是寫一個服務然后在客戶端調用么?這里請允許我迷之一笑~Naive!本文簡單地介紹一下兩種形式的C/S架構&am…

MTK-TP(電阻屏校準程序ts_lib移植)

現今的項目中已經很少有使用電阻TP,但總有些奇怪的需求。如果項目中遇到需要校準電阻屏如何保證較快且較穩的調試TP呢。這里介紹使用ts_lib庫來進行調試。 當然也可以使用一些常見的校準算法,采集5點,但最終的公式應該是不變的: X…

mac vscode 實用快捷鍵

cmddel:光標左邊刪到頭 cmdfndel:光標右側刪到頭轉載于:https://www.cnblogs.com/smzd/p/11474488.html

ONENET讀取與控制麒麟座MINI開發板LED狀態

硬件 麒麟座MINI開發板V1.4 嵌入式軟件 OneNET_Demo_ESP8266_EDP_Led 工程修改內容 led.c文件修改 函數LED_Init,mini開發板LED所在GPIO為PB6、PB7、PB8、PB9 函數LED_GetValue,mini開發板LED狀態與IO口狀態相反 /** * brief LED指示燈初始化函數**/v…

洛谷 - P1217 - 回文質數 - 枚舉

https://www.luogu.org/problemnew/show/P1217 考慮暴力生成所有的回文數然后再判斷是不是質數。注意個位的選擇實際上只有4種。所以是 $4*10^3*10^34*10^6$ &#xff0c;完全充裕的復雜度。 #include<bits/stdc.h> using namespace std; #define ll long longint a,b; v…

git commit之后,想撤銷commit

寫完代碼后&#xff0c;我們一般這樣git add . //添加所有文件git commit -m "本功能全部完成"執行完commit后&#xff0c;想撤回commit&#xff0c;怎么辦&#xff1f;這樣涼拌&#xff1a;git reset --soft HEAD^這樣就成功的撤銷了你的commit注意&#xff0c;僅僅…

引用數據類型

1.Scanner類 Scanner類是引用數據類型的一種&#xff0c;我們可以使用該類來完成用戶鍵盤錄入&#xff0c;獲取到錄入的數據。 引用數據類型的使用&#xff1a; 與定義基本數據類型變量不同&#xff0c;引用數據類型的變量定義及賦值有一個相對固定的步驟或格式。 數據類型 變…

phpmyadmin登錄遠程mysql數據庫

之前只用phpmyadmin登錄本地的mysql&#xff0c;管理另一個遠程數據庫的時候發現&#xff0c;單純用命令行處理字符串、換行符實在是不好使&#xff0c;所以配置了遠程登錄mysql&#xff0c;很簡單的問題結果沒有搜到合適的方法&#xff0c;所以記錄下我的配置方式。 phpmyadmi…

activemq的使用場景

一、消息隊列概述 消息隊列中間件是分布式系統中重要的組件&#xff0c;主要解決應用耦合&#xff0c;異步消息&#xff0c;流量削鋒等問題。實現高性能&#xff0c;高可用&#xff0c;可伸縮和最終一致性架構。是大型分布式系統不可缺少的中間件。 目前在生產環境&#xff0c…

復習JavaScript隨手記

數據類型 基本類型 stringnumberbooleanundefinednumber類型,包含整數浮點數 NaN和自己都不相等,涉及NaN的計算結果都是NaN isNaN()函數用于判斷一個數是不是NaN 引用類型 object類型 function類型 繼承自object object類型定義了prototype屬性 可以通過它動態給對象綁定方法和…

TP5在前端時間戳轉換為時間格式

value"{:date(Y-m-d H:i:s,$data[add_date])}" 例如&#xff1a; <td>{:date(Y-m-d H:i:s,$d[create_time])}</td> 轉載于:https://www.cnblogs.com/shark1100913/p/9468077.html

Java(發布/訂閱模式)

1、概述 觀察者模式又稱為發布/訂閱(Publish/Subscribe)模式 觀察者設計模式涉及到兩種角色&#xff1a;主題&#xff08;Subject&#xff09;和觀察者&#xff08;Observer&#xff09; &#xff08;1&#xff09;Subject模塊 Subjec模塊有3個主要操作 addObserver()&#…

VUE $SET源碼

轉載于:https://www.cnblogs.com/smzd/p/11634255.html

JS 日期格式化

1、將中國標準時間格式化為&#xff08;2017-06-06 15:05:04&#xff09; function formatDateTime(theDate) { var _hour theDate.getHours(); var _minute theDate.getMinutes(); var _second theDate.getSeconds(); var _year theDate.getFullYear() var _month theDat…

canvas 入門

<canvas>是HTML5新增的&#xff0c;是可以使用腳本&#xff08;JavaScript&#xff09;在其中繪制圖像的HTML元素。 canvas是由HTML代碼配合高度和寬度屬性而定義出的可繪制區域&#xff0c;JavaScript代碼可訪問該區域&#xff0c;類似于其它通用的二維API&#xff0c;通…

Java實現消息隊列服務

使用 JAVA 語言自己動手來寫一個MQ (類似ActiveMQ,RabbitMQ) 主要角色 首先我們必須需要搞明白 MQ (消息隊列) 中的三個基本角色 ProducerBrokerConsumer 整體架構如下所示 自定義協議 首先從上一篇中介紹了協議的相關信息,具體廠商的 MQ(消息隊列) 需要遵循某種協議或者…

Knockout中ko.utils中處理數組的方法集合

每一套框架基本上都會有一個工具類&#xff0c;如&#xff1a;Vue中的Vue.util、Knockout中的ko.utils、jQuery直接將一些工具類放到了$里面&#xff0c;如果你還需要更多的工具類可以試試lodash。本文只介紹一下Knockout中ko.utils中處理數組的一些方法。 ko.utils.arrayForEa…

$nextTick 源碼

x現在沒時間&#xff0c;留個坑 轉載于:https://www.cnblogs.com/smzd/p/11634665.html