gRPC 學(xué)習(xí)筆記

?gRPC 學(xué)習(xí)筆記,記錄gprc一些基本概念.

?gRPC正如其他 RPC 系統(tǒng),gRPC 基于如下思想:定義一個(gè)服務(wù),指定其可以被遠(yuǎn)程調(diào)用的方法及其參數(shù)和返回類(lèi)型。gRPC 默認(rèn)使用 protocol buffers 作為接口定義語(yǔ)言,來(lái)描述服務(wù)接口和有效載荷消息結(jié)構(gòu)。如果有需要的話,可以使用其他替代方案。

gRPC是基于HTTP/2協(xié)議的,要深刻理解 gRPC協(xié)議,就有必要理解一下 HTTP/2協(xié)議.

gRPC是什么

gRPC 一開(kāi)始由 google 開(kāi)發(fā),是一款語(yǔ)言中立、平臺(tái)中立、開(kāi)源的遠(yuǎn)程過(guò)程調(diào)用(RPC)系統(tǒng).

在 gRPC 里客戶端應(yīng)用可以像調(diào)用本地對(duì)象一樣直接調(diào)用另一臺(tái)不同的機(jī)器上服務(wù)端應(yīng)用的方法,使得您能夠更容易地創(chuàng)建分布式應(yīng)用和服務(wù)。與許多 RPC 系統(tǒng)類(lèi)似,gRPC 也是基于以下理念:定義一個(gè)服務(wù),指定其能夠被遠(yuǎn)程調(diào)用的方法(包含參數(shù)和返回類(lèi)型)。在服務(wù)端實(shí)現(xiàn)這個(gè)接口,并運(yùn)行一個(gè) gRPC 服務(wù)器來(lái)處理客戶端調(diào)用。在客戶端擁有一個(gè)存根能夠像服務(wù)端一樣的方法。

gRPC 客戶端和服務(wù)端可以在多種環(huán)境中運(yùn)行和交互 - 從 google 內(nèi)部的服務(wù)器到你自己的筆記本,并且可以用任何 gRPC 支持的語(yǔ)言來(lái)編寫(xiě)。所以,你可以很容易地用 Java 創(chuàng)建一個(gè) gRPC 服務(wù)端,用 Go、Python、Ruby 來(lái)創(chuàng)建客戶端。此外,Google 最新 API 將有 gRPC 版本的接口,使你很容易地將 Google 的功能集成到你的應(yīng)用里。

更多跨語(yǔ)言跨平臺(tái)支持請(qǐng)看這里

gRPC架構(gòu)

image

如上圖所示,gRPC 的代碼結(jié)構(gòu)主要分為三層:

  • 運(yùn)輸層,最低層,基于 Http2.0 和 SSL。
  • 通道層(Channel層),核心的 C 代碼,實(shí)現(xiàn)與運(yùn)輸層的交互。
  • 應(yīng)用層,各種語(yǔ)言的實(shí)現(xiàn),實(shí)現(xiàn)各種語(yǔ)言調(diào)用通道層的 C 代碼。

PS: gRPC 的 Java 和 Go 語(yǔ)言版本不由上面架構(gòu)實(shí)現(xiàn),Java 和 Go 有自己的高性能網(wǎng)絡(luò)庫(kù)。

protocol buffers

gRPC 默認(rèn)使用 protocol buffers,這是 Google 開(kāi)源的一套成熟的結(jié)構(gòu)數(shù)據(jù)序列化機(jī)制(當(dāng)然也可以使用其他數(shù)據(jù)格式如 JSON)。你可以用 proto files 創(chuàng)建 gRPC 服務(wù),用 protocol buffers 消息類(lèi)型來(lái)定義方法參數(shù)和返回類(lèi)型。

服務(wù)定義

正如其他 RPC 系統(tǒng),gRPC 基于如下思想:定義一個(gè)服務(wù), 指定其可以被遠(yuǎn)程調(diào)用的方法及其參數(shù)和返回類(lèi)型。gRPC 默認(rèn)使用 protocol buffers 作為接口定義語(yǔ)言,來(lái)描述服務(wù)接口和有效載荷消息結(jié)構(gòu)。如果有需要的話,可以使用其他替代方案。

service HelloService {
  rpc SayHello (HelloRequest) returns (HelloResponse);
}

message HelloRequest {
  required string greeting = 1;
}

message HelloResponse {
  required string reply = 1;
}

gRPC 允許你定義四類(lèi)服務(wù)方法:

  • 單項(xiàng) RPC,即客戶端發(fā)送一個(gè)請(qǐng)求給服務(wù)端,從服務(wù)端獲取一個(gè)應(yīng)答,就像一次普通的函數(shù)調(diào)用。
rpc SayHello(HelloRequest) returns (HelloResponse){
}
  • 服務(wù)端流式 RPC,即客戶端發(fā)送一個(gè)請(qǐng)求給服務(wù)端,可獲取一個(gè)數(shù)據(jù)流用來(lái)讀取一系列消息。客戶端從返回的數(shù)據(jù)流里一直讀取直到?jīng)]有更多消息為止。
rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse){
}
  • 客戶端流式 RPC,即客戶端用提供的一個(gè)數(shù)據(jù)流寫(xiě)入并發(fā)送一系列消息給服務(wù)端。一旦客戶端完成消息寫(xiě)入,就等待服務(wù)端讀取這些消息并返回應(yīng)答。
rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse) {
}
  • 雙向流式 RPC,即兩邊都可以分別通過(guò)一個(gè)讀寫(xiě)數(shù)據(jù)流來(lái)發(fā)送一系列消息。這兩個(gè)數(shù)據(jù)流操作是相互獨(dú)立的,所以客戶端和服務(wù)端能按其希望的任意順序讀寫(xiě),例如:服務(wù)端可以在寫(xiě)應(yīng)答前等待所有的客戶端消息,或者它可以先讀一個(gè)消息再寫(xiě)一個(gè)消息,或者是讀寫(xiě)相結(jié)合的其他方式。每個(gè)數(shù)據(jù)流里消息的順序會(huì)被保持。
rpc BidiHello(stream HelloRequest) returns (stream HelloResponse){
}

使用 API 接口

gRPC 提供 protocol buffer 編譯插件,能夠從一個(gè)服務(wù)定義的 .proto 文件生成客戶端和服務(wù)端代碼。通常 gRPC 用戶可以在服務(wù)端實(shí)現(xiàn)這些API,并從客戶端調(diào)用它們。

  • 在服務(wù)側(cè),服務(wù)端實(shí)現(xiàn)服務(wù)接口,運(yùn)行一個(gè) gRPC 服務(wù)器來(lái)處理客戶端調(diào)用。gRPC 底層架構(gòu)會(huì)解碼傳入的請(qǐng)求,執(zhí)行服務(wù)方法,編碼服務(wù)應(yīng)答。
  • 在客戶側(cè),客戶端有一個(gè)存根實(shí)現(xiàn)了服務(wù)端同樣的方法??蛻舳丝梢栽诒镜卮娓{(diào)用這些方法,用合適的 protocol buffer 消息類(lèi)型封裝這些參數(shù)— gRPC 來(lái)負(fù)責(zé)發(fā)送請(qǐng)求給服務(wù)端并返回服務(wù)端 protocol buffer 響應(yīng)。

同步 vs 異步

同步 RPC 調(diào)用一直會(huì)阻塞直到從服務(wù)端獲得一個(gè)應(yīng)答,這與 RPC 希望的抽象最為接近。另一方面網(wǎng)絡(luò)內(nèi)部是異步的,并且在許多場(chǎng)景下能夠在不阻塞當(dāng)前線程的情況下啟動(dòng) RPC 是非常有用的。

在多數(shù)語(yǔ)言里,gRPC 編程接口同時(shí)支持同步和異步的特點(diǎn)。

RPC 生命周期

現(xiàn)在讓我們來(lái)仔細(xì)了解一下當(dāng) gRPC 客戶端調(diào)用 gRPC 服務(wù)端的方法時(shí)到底發(fā)生了什么。

單項(xiàng) RPC

首先我們來(lái)了解一下最簡(jiǎn)單的 RPC 形式:客戶端發(fā)出單個(gè)請(qǐng)求,獲得單個(gè)響應(yīng)。

  • 一旦客戶端通過(guò)樁調(diào)用一個(gè)方法,服務(wù)端會(huì)得到相關(guān)通知 ,通知包括客戶端的元數(shù)據(jù),方法名,允許的響應(yīng)期限(如果可以的話)

  • 服務(wù)端既可以在任何響應(yīng)之前直接發(fā)送回初始的元數(shù)據(jù),也可以等待客戶端的請(qǐng)求信息,到底哪個(gè)先發(fā)生,取決于具體的應(yīng)用.

  • 一旦服務(wù)端獲得客戶端的請(qǐng)求信息,就會(huì)做所需的任何工作來(lái)創(chuàng)建或組裝對(duì)應(yīng)的響應(yīng)。如果成功的話,這個(gè)響應(yīng)會(huì)和包含狀態(tài)碼以及可選的狀態(tài)信息等狀態(tài)明細(xì)及可選的追蹤信息返回給客戶端 。

  • 假如狀態(tài)是 OK 的話,客戶端會(huì)得到應(yīng)答,這將結(jié)束客戶端的調(diào)用。

服務(wù)端流式 RPC

服務(wù)端流式 RPC 除了在得到客戶端請(qǐng)求信息后發(fā)送回一個(gè)應(yīng)答流之外,與我們的簡(jiǎn)單例子一樣。在發(fā)送完所有應(yīng)答后,服務(wù)端的狀態(tài)詳情(狀態(tài)碼和可選的狀態(tài)信息)和可選的跟蹤元數(shù)據(jù)被發(fā)送回客戶端,以此來(lái)完成服務(wù)端的工作??蛻舳嗽诮邮盏剿蟹?wù)端的應(yīng)答后也完成了工作。

客戶端流式 RPC

客戶端流式 RPC 也基本與我們的簡(jiǎn)單例子一樣,區(qū)別在于客戶端通過(guò)發(fā)送一個(gè)請(qǐng)求流給服務(wù)端,取代了原先發(fā)送的單個(gè)請(qǐng)求。服務(wù)端通常(但并不必須)會(huì)在接收到客戶端所有的請(qǐng)求后發(fā)送回一個(gè)應(yīng)答,其中附帶有它的狀態(tài)詳情和可選的跟蹤數(shù)據(jù)。

雙向流式 RPC

雙向流式 RPC ,調(diào)用由客戶端調(diào)用方法來(lái)初始化,而服務(wù)端則接收到客戶端的元數(shù)據(jù),方法名和截止時(shí)間。服務(wù)端可以選擇發(fā)送回它的初始元數(shù)據(jù)或等待客戶端發(fā)送請(qǐng)求。

下一步怎樣發(fā)展取決于應(yīng)用,因?yàn)榭蛻舳撕头?wù)端能在任意順序上讀寫(xiě) - 這些流的操作是完全獨(dú)立的。例如服務(wù)端可以一直等直到它接收到所有客戶端的消息才寫(xiě)應(yīng)答,或者服務(wù)端和客戶端可以像"乒乓球"一樣:服務(wù)端后得到一個(gè)請(qǐng)求就回送一個(gè)應(yīng)答,接著客戶端根據(jù)應(yīng)答來(lái)發(fā)送另一個(gè)請(qǐng)求,以此類(lèi)推。

截止時(shí)間

gRPC 允許客戶端在調(diào)用一個(gè)遠(yuǎn)程方法前指定一個(gè)最后期限值。這個(gè)值指定了在客戶端可以等待服務(wù)端多長(zhǎng)時(shí)間來(lái)應(yīng)答,超過(guò)這個(gè)時(shí)間值 RPC 將結(jié)束并返回DEADLINE_EXCEEDED錯(cuò)誤。在服務(wù)端可以查詢這個(gè)期限值來(lái)看是否一個(gè)特定的方法已經(jīng)過(guò)期,或者還剩多長(zhǎng)時(shí)間來(lái)完成這個(gè)方法。
各語(yǔ)言來(lái)指定一個(gè)截止時(shí)間的方式是不同的 - 比如在 Python 里一個(gè)截止時(shí)間值總是必須的,但并不是所有語(yǔ)言都有一個(gè)默認(rèn)的截止時(shí)間。

RPC 終止

在 gRPC 里,客戶端和服務(wù)端對(duì)調(diào)用成功的判斷是獨(dú)立的、本地的,他們的結(jié)論可能不一致。這意味著,比如你有一個(gè) RPC 在服務(wù)端成功結(jié)束("我已經(jīng)返回了所有應(yīng)答!"),到那時(shí)在客戶端可能是失敗的("應(yīng)答在最后期限后才來(lái)到!")。也可能在客戶端把所有請(qǐng)求發(fā)送完前,服務(wù)端卻判斷調(diào)用已經(jīng)完成了。

取消 RPC

無(wú)論客戶端還是服務(wù)端均可以再任何時(shí)間取消一個(gè) RPC 。一個(gè)取消會(huì)立即終止 RPC 這樣可以避免更多操作被執(zhí)行。它不是一個(gè)"撤銷(xiāo)", 在取消前已經(jīng)完成的不會(huì)被回滾。當(dāng)然,通過(guò)同步調(diào)用的 RPC 不能被取消,因?yàn)橹钡?RPC 結(jié)束前,程序控制權(quán)還沒(méi)有交還給應(yīng)用。

元數(shù)據(jù)集

元數(shù)據(jù)是一個(gè)特殊 RPC 調(diào)用對(duì)應(yīng)的信息(授權(quán)詳情]) ,這些信息以鍵值對(duì)的形式存在,一般鍵的類(lèi)型是字符串,值的類(lèi)型一般也是字符串(當(dāng)然也可以是二進(jìn)制數(shù)據(jù))。元數(shù)據(jù)對(duì) gRPC 本事來(lái)說(shuō)是不透明的 - 它讓客戶端提供調(diào)用相關(guān)的信息給服務(wù)端,反之亦然。

對(duì)于元數(shù)據(jù)的訪問(wèn)是語(yǔ)言相關(guān)的。

channel

在創(chuàng)建客戶端存根時(shí),一個(gè) gRPC channel 提供一個(gè)特定主機(jī)和端口服務(wù)端的連接??蛻舳丝梢酝ㄟ^(guò)指定 channel 參數(shù)來(lái)修改 gRPC 的默認(rèn)行為,比如打開(kāi)關(guān)閉消息壓縮。一個(gè) chennel 具有狀態(tài),包含已連接和空閑 。

gRPC 如何處理關(guān)閉 channel 是語(yǔ)言相關(guān)的。有些語(yǔ)言可允許詢問(wèn)頻道狀態(tài)。

最后編輯于
?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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