Thrift基本原理及使用

參考文章RPC 基本原理與 Apach Thrift 初體驗

RPC基本原理

RPC(Remote Procedure Call),遠程過程調用,大部分的RPC框架都遵循如下三個開發步驟:

1. 定義一個接口說明文件:描述了對象(結構體)、對象成員、接口方法等一系列信息;
2. 通過RPC框架所提供的編譯器,將接口說明文件編譯成具體的語言文件;
3. 在客戶端和服務器端分別引入RPC編譯器所生成的文件,即可像調用本地方法一樣調用服務端代碼;

RPC通信過程如下圖所示
RPC通信過程
通信過程包括以下幾個步驟:

1、客戶過程以正常方式調用客戶樁(client stub,一段代碼);
2、客戶樁生成一個消息,然后調用本地操作系統;
3、客戶端操作系統將消息發送給遠程操作系統;
4、遠程操作系統將消息交給服務器樁(server stub,一段代碼);
5、服務器樁將參數提取出來,然后調用服務器過程;
6、服務器執行要求的操作,操作完成后將結果返回給服務器樁;
7、服務器樁將結果打包成一個消息,然后調用本地操作系統;
8、服務器操作系統將含有結果的消息發送回客戶端操作系統;
9、客戶端操作系統將消息交給客戶樁;
10、客戶樁將結果從從消息中提取出來,返回給調用它的客戶過程;

所有這些步驟的效果是,將客戶過程對客戶樁發出的本地調用轉換成對服務器過程的本地調用,而客戶端和服務器都不會意識到有中間步驟的存在。

這個時候,你可能會想,既然是調用另一臺機器的服務,使用 RESTful API 也可以實現啊,為什么要選擇 RPC 呢?我們可以從兩個方面對比:

  • 資源粒度。RPC 就像本地方法調用,RESTful API 每一次添加接口都可能需要額外地組織開放接口的數據,這相當于在應用視圖中再寫了一次方法調用,而且它還需要維護開發接口的資源粒度、權限等;
  • 流量消耗。RESTful API 在應用層使用 HTTP 協議,哪怕使用輕型、高效、傳輸效率高的 JSON 也會消耗較大的流量,而 RPC 傳輸既可以使用 TCP 也可以使用 UDP,而且協議一般使用二制度編碼,大大降低了數據的大小,減少流量消耗。

對接異構第三方服務時,通常使用 HTPP/RESTful 等公有協議,對于內部的服務調用,應用選擇性能更高的二進制私有協議。

Thrift架構

thrift主要用于各個服務之間的RPC通信,支持跨語言。thrift是一個典型的CS結構,客戶端和服務端可以使用不同的語言開發,thrift通過IDL(Interface Description Language)來關聯客戶端和服務端。thrift的整體架構圖如下圖所示

thrift架構


圖中Your Code是用戶實現的業務邏輯,接下來的FooService.ClientFoo.write()/read()是thrift根據IDL生成的客戶端和服務端的代碼,對應于RPC中Client stub和Server stub。TProtocol 用來對數據進行序列化與反序列化,具體方法包括二進制,JSON 或者 Apache Thrift 定義的格式。TTransport 提供數據傳輸功能,使用 Apache Thrift 可以方便地定義一個服務并選擇不同的傳輸協議。
如下圖所示為thrift的網絡棧結構

thrift網絡棧結構

thirft使用socket進行數據傳輸,數據以特定的格式發送,接收方進行解析。我們定義好thrift的IDL文件后,就可以使用thrift的編譯器來生成雙方語言的接口、model,在生成的model以及接口代碼中會有解碼編碼的代碼。

TTransport層

代表thrift的數據傳輸方式,thrift定義了如下幾種常用數據傳輸方式

  • TSocket: 阻塞式socket;
  • TFramedTransport: 以frame為單位進行傳輸,非阻塞式服務中使用;
  • TFileTransport: 以文件形式進行傳輸;

TProtocol層

代表thrift客戶端和服務端之間傳輸數據的協議,通俗來講就是客戶端和服務端之間傳輸數據的格式(例如json等),thrift定義了如下幾種常見的格式

  • TBinaryProtocol: 二進制格式;
  • TCompactProtocol: 壓縮格式;
  • TJSONProtocol: JSON格式;
  • TSimpleJSONProtocol: 提供只寫的JSON協議;

thrift支持的Server模型

thrift主要支持以下幾種服務模型

  • TSimpleServer: 簡單的單線程服務模型,常用于測試;
  • TThreadPoolServer: 多線程服務模型,使用標準的阻塞式IO;
  • TNonBlockingServer: 多線程服務模型,使用非阻塞式IO(需要使用TFramedTransport數據傳輸方式);
  • THsHaServer: THsHa引入了線程池去處理,其模型讀寫任務放到線程池去處理,Half-sync/Half-async處理模式,Half-async是在處理IO事件上(accept/read/write io),Half-sync用于handler對rpc的同步處理;

thrift IDL文件

thrift IDL不支持無符號的數據類型,因為很多編程語言中不存在無符號類型,thrift支持一下幾種基本的數據類型

  • byte: 有符號字節
  • i16: 16位有符號整數
  • i32: 32位有符號整數
  • i64: 63位有符號整數
  • double: 64位浮點數
  • string: 字符串

此外thrift還支持以下容器類型:

  • list: 一系列由T類型的數據組成的有序列表,元素可以重復;
  • set: 一系列由T類型的數據組成的無序集合,元素不可重復;
  • map: 一個字典結構,Key為K類型,Value為V類型,相當于java中的HashMap;

thrift容器中元素的類型可以是除了service之外的任何類型,包括exception

thirft支持struct類型,目的就是講一些數據聚合在一起,方便傳輸管理,struct定義形式如下:

struct People {1:string name;2:i32 age;3:string gender;
}

thrift支持枚舉類型,定義形式如下:

enum Gender {MALE,FEMALE
}

thrift支持自定義異常類型exception,異常定義形式如下:

exception RequestException {1:i32 code;2:string reason;
}

thrift定義服務相當于Java中創建接口一樣,創建的service經過代碼生thrift代碼生成工具編譯后就會生成客戶端和服務端的框架代碼,service的定義形式如下:

service HelloWorldService {// service中可以定義若干個服務,相當于Java Interface中定義的方法string doAction(1:string name, 2:i32 age);
}

thrift支持給類型定義別名,如下所示:

typedef i32 int
typedef i64 long

thrift也支持常量的定義,使用const關鍵字:

const i32 MAX_RETRIES_TIME = 10;
const string MY_WEBSITE = "http://facebook.com";

thrift支持命名空間,命名空間相當于Java中的package,主要用于組織代碼,thrift使用關鍵字namespace定義命名空間,格式是namespace 語言名 路徑,如下示例所示:

namespace java com.test.thrift.demo

thrift也支持文件包含,相當于CPP中的include,Java中的import,使用關鍵字include:

include "global.thrift"

#///**/都可以作為thrift文件中的注釋。

thrift提供兩個關鍵字requiredoptional,分別用于表示對應的字段是必填的還是可選的(推薦盡量使用optional),如下所示:

struct People {1:required string name;2:optional i32 age;
}

thrift應用示例

本示例中我們使用java編寫thrift的服務端程序,使用python編寫thrift的客戶端程序。

首先定義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 String// struct關鍵字用于定義結構體,相當于面向對象編程語言中的類
struct Person {// 相當于定義類中的成員,并生成相應的get和set方法,optional表示username這個成員可以沒有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 data),void savePerson(1: required Person person)
}

執行thrift --gen java src/thrift/data.thrift生成對應的java代碼,并引入到Java工程當中,代碼結構如下圖所示

thrift示例代碼結構

編寫Java服務端代碼,data.thrift的service中定義了兩個服務,我們需要定義相應服務的實現類(相當于handler),如下所示:

import thrift.generated.DataException;
import thrift.generated.Person;
import thrift.generated.PersonService;public class PersonServiceImpl implements PersonService.Iface {@Overridepublic Person getPersonByUsername(String username) throws DataException {System.out.println("Got Client Param: " + username);return new Person().setUsername(username).setAge(20).setMarried(false);}@Overridepublic void savePerson(Person person) throws DataException {System.out.println("Got Client Param:");System.out.println(person.username);System.out.println(person.age);System.out.println(person.married);}
}

同時我們需要借助thrift為我們提供的類庫實現一個服務器來監聽rpc請求,代碼如下所示:

import org.apache.thrift.TProcessorFactory;
import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.server.THsHaServer;
import org.apache.thrift.server.TServer;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TNonblockingServerSocket;
import thrift.generated.PersonService;public class ThriftServer {public static void main(String[] args) throws Exception {// 定義服務器使用的socket類型TNonblockingServerSocket tNonblockingServerSocket = new TNonblockingServerSocket(8899);// 創建服務器參數THsHaServer.Args arg = new THsHaServer.Args(tNonblockingServerSocket).minWorkerThreads(2).maxWorkerThreads(4);// 請求處理器PersonService.Processor<PersonServiceImpl> processor = new PersonService.Processor<>(new PersonServiceImpl());// 配置傳輸數據的格式arg.protocolFactory(new TCompactProtocol.Factory());// 配置數據傳輸的方式arg.transportFactory(new TFramedTransport.Factory());// 配置處理器用來處理rpc請求arg.processorFactory(new TProcessorFactory(processor));// 本示例中使用半同步半異步方式的服務器模型TServer server = new THsHaServer(arg);System.out.println("Thrift Server Started!");// 啟動服務server.serve();}
}

編寫python客戶端,執行thrift --gen py src/thrift/data.thrift生成對應的python代碼,并引入到python工程當中,代碼結構如下圖所示

thrift python代碼結構


python客戶端代碼如下所示:

# -*- coding:utf-8 -*-
__author__ = 'kpzhang'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(900)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)transport.close()except Thrift.TException, tx:print '%s' % tx.message

客戶端可以向調用本地的方法一樣調用服務端的方法。


---------------------
作者:zkp_java
來源:CSDN
原文:https://blog.csdn.net/zkp_java/article/details/81879577
版權聲明:本文為作者原創文章,轉載請附上博文鏈接!
內容解析By:CSDN,CNBLOG博客文章一鍵轉載插件

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

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

相關文章

01-H5語義化標簽

轉載于:https://www.cnblogs.com/Zeki/p/5901399.html

JSON 解析的兩種方法

今天幫朋友看了下JSON解析結果 eval解析JSON中的注意點在JS中將JSON的字符串解析成JSON數據格式&#xff0c;一般有兩種方式&#xff1a; 1.一種為使用eval()函數。 2. 使用Function對象來進行返回解析。 使用eval函數來解析&#xff0c;并且使用jquery的each方法來遍歷 用jque…

配置中心 App Configuration (三):配置的動態更新

Get Azure key-value pairs from App configuration | Serverless360寫在前面我在前文&#xff1a;《微軟Azure配置中心 App Configuration (一)&#xff1a;輕松集成到Asp.Net Core》已經介紹了Asp.net Core怎么輕易的接入azure 配置中心App Configuration(下稱azure 配置中心…

萬字總結 JS 數據結構與常用的算法

前言 首先&#xff0c;為什么我會學習數據結構與算法呢&#xff0c;其實主要是有兩方面 第一&#xff0c;是我在今年的flag里明確說到我會學這個東西第二&#xff0c;學了這些&#xff0c;對自己以后在工作或者面試也會帶來許多好處然后&#xff0c;本文是最近學習的一個總結文…

精通Java設計模式從初見到相愛之工廠+策略模式(3)

為什么80%的碼農都做不了架構師&#xff1f;>>> 1、公司項目需求。 用戶簽到活動&#xff0c;會員簽到怎么處理&#xff0c;超級會員怎么處理&#xff0c;普通用戶簽到怎么處理&#xff0c;針對不同的檔次&#xff0c;有不同的方案&#xff0c;所以在項目中用到了策…

jquery weui 中alert彈出框在ios中跳動問題

問題描述&#xff1a; jquery-weui中的彈出框在ios上會有一個右下角向中間滑動的效果&#xff0c;在Android上沒有這個效果。 解決方法&#xff1a; 修該jquery-weui.js中的openModal方法如下圖: 轉載于:https://www.cnblogs.com/xianZJ/p/6773097.html

WPF效果第一百九十五篇之又玩ListBox

ListBox一直是我的最愛;今天再次基于他玩耍一下不一樣的效果;閑話不多扯直接看效果:1、這次直接用的ItemContainerStyle:2、通過HitTest實現點選邊框&#xff1a;Point point e.GetPosition(LightDarkListBox); VisualTreeHelper.HitTest(LightDarkListBox, new HitTestFilter…

Web3,互聯網新造神“機器”?

本文來自微信公眾號&#xff1a;每經頭條 &#xff08;ID&#xff1a;nbdtoutiao&#xff09;&#xff0c;作者&#xff1a;李蕾&#xff0c;編輯&#xff1a;肖芮冬&#xff0c;頭圖來自&#xff1a;視覺中國 “與目前的互聯網相比&#xff0c;Web3基于區塊鏈等底層技術&#…

Gradle實戰:發布aar包到maven倉庫

查看原文&#xff1a;http://blog.csdn.net/u0108184... Gradle實戰系列文章&#xff1a;《Gradle基本知識點與常用配置》《Gradle實戰&#xff1a;Android多渠道打包方案匯總》《Gradle實戰&#xff1a;不同編譯類型的包同設備共存》《Gradle實戰&#xff1a;執行sql操作hive…

synchronized與Lock的區別

類別synchronizedLock存在層次Java的關鍵字&#xff0c;在jvm層面上是一個類鎖的釋放1、以獲取鎖的線程執行完同步代碼&#xff0c;釋放鎖 2、線程執行發生異常&#xff0c;jvm會讓線程釋放鎖在finally中必須釋放鎖&#xff0c;不然容易造成線程死鎖鎖的獲取假設A線程獲得鎖&am…

even兼容

var eventarguments.callee.caller.arguments[0]||window.event;//消除瀏覽器差異 var ewindow.event||event; //消除瀏覽器差異 轉載于:https://www.cnblogs.com/webqiand/articles/11250768.html

普通中年人的真實出路

閱讀本文大概需要6分鐘。互聯網人甚至中國整體的用工市場的確有中年淘汰的問題&#xff0c;我們可以當它不存在&#xff0c;甚至當有人給出解法的時候&#xff0c;我們也可以認為他們在傳播焦慮&#xff0c;但事實就是事實&#xff0c;它的存在不隨個人意愿而轉移。最近抖音上有…

項目管理常見的問題

綜合管理 缺乏企業級的項目管理平臺;項目目標不清楚;項目經理不了解項目管理流程和工具;項目模板不統一;計劃意識薄弱&#xff0c;缺乏規范的分解。難以過程監控&#xff0c;實時地了解項目進度,靠手工統計和匯報項目進度&#xff0c;難以真實反映進度。項目控制不力&#xff0…

常用小提示

阿里云Linux安裝軟件鏡像源 第一步&#xff1a;備份你的原鏡像文件&#xff0c;以免出錯后可以恢復。 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup第二步&#xff1a;下載新的CentOS-Base.repo 到/etc/yum.repos.d/ CentOS 5 wget -O /etc…

抽象工廠模式(Absraact Factory)介紹與實現

創建一個IProduct,后面模擬業務時要用到 package com.xiawei.factory; public class IProduct { private String productNo "";} package com.xiawei.factory;/** * 規范工廠接口 </p> *///創建一個所有工廠的規范接口,后面所有的工廠類都要來實現這個接口,并…

【溫故知新】C# Linq中 Select SelectMany 使用技巧

微信公眾號&#xff1a;趣編程ACE關注可了解更多的.NET日常實戰開發技巧&#xff0c;如需源碼 后臺回復 源碼 即可;如果覺得對你有幫助&#xff0c;歡迎關注C# Linq中 Select && SelectMany 使用技巧Select 和 SelectMany 是我們開發中對集合常用的兩個擴展方法&#x…

bzoj4870

http://www.lydsy.com/JudgeOnline/problem.php?id4870 矩陣快速冪。。。 人話題意&#xff1a;從nk個物品里選模k余r個物品&#xff0c;問方案數模P 那么我們有方程 f[i][j]f[i-1][j]f[i-1][j-1] 跟組合數一個樣子 j∈(0,k) 這個物品選還是不選加起來 構造矩陣&#xff1a;x.…

15000 字的 SQL 語句大全,值得收藏!

基礎 1、說明&#xff1a;創建數據庫 CREATE DATABASE database-name 2、說明&#xff1a;刪除數據庫 drop database dbname 3、說明&#xff1a;備份sql server --- 創建 備份數據的 device USE master EXEC sp_addumpdevice disk, testBack, c:\mssql7backup\MyNwind_1.dat -…

Codeforces Round #410 (Div. 2) D. Mike and distribution 思維+數學

鏈接&#xff1a; http://codeforces.com/contest/798/problem/D 題意&#xff1a; 給你兩個長度為n的數列a和b&#xff0c;讓你選n/21個下標&#xff0c;使得2*∑ai>suma,2*∑bi>sumb 題解1&#xff1a; 用一個叫random_shuffle的東西&#xff0c;每次都亂選&#xff0c…

PerfView專題 (第三篇):如何尋找 C# 中的 VirtualAlloc 內存泄漏

一&#xff1a;背景 上一篇我們聊到了如何用 PerfView 去偵察 NTHeap 的內存泄漏&#xff0c;這種內存泄漏往往是用 C 的 malloc 或者 C 的 new 分配而不釋放所造成的&#xff0c;這一篇我們來聊一下由 VirtualAlloc 方法造成的泄漏如何去甄別&#xff1f;了解 VirtualAlloc 的…