HTTP之gRPC

gRPC 官方文檔html

 

gRPC 是一個高性能、開源和通用的 RPC 框架,面向移動和 HTTP/2 設計。編程

 

gRPC 基於 HTTP/2 標準設計,帶來諸如雙向流、流控、頭部壓縮、單 TCP 鏈接上的多複用請求等特。json

這些特性使得其在移動設備上表現更好,更省電和節省空間佔用。api

 

gRPC 一開始由 google 開發,是一款語言中立、平臺中立、開源的遠程過程調用(RPC)系統。安全

 

 

gRPC 是什麼?

在 gRPC 裏客戶端應用能夠像調用本地對象同樣直接調用另外一臺不一樣的機器上服務端應用的方法,使得您可以更容易地建立分佈式應用和服務。服務器

與許多 RPC 系統相似,gRPC 也是基於如下理念:定義一個服務,指定其可以被遠程調用的方法(包含參數和返回類型)。網絡

在服務端實現這個接口,並運行一個 gRPC 服務器來處理客戶端調用。架構

在客戶端擁有一個存根可以像服務端同樣的方法。併發

 

 gRPC 客戶端和服務端能夠在多種環境中運行和交互 - 從 google 內部的服務器到你本身的筆記本,而且能夠用任何 gRPC 支持的語言來編寫。app

因此,你能夠很容易地用 Java 建立一個 gRPC 服務端,用 Go、Python、Ruby 來建立客戶端。

此外,Google 最新 API 將有 gRPC 版本的接口,使你很容易地將 Google 的功能集成到你的應用裏。

 

 

 

gRPC 概念

經過對於 gRPC 的架構和 RPC 生命週期的概覽來介紹 gRPC 的主要概念。

服務定義

正如其餘 RPC 系統,gRPC 基於以下思想:定義一個服務, 指定其能夠被遠程調用的方法及其參數和返回類型。

gRPC 默認使用 protocol buffers 做爲接口定義語言,來描述服務接口和有效載荷消息結構。若是有須要的話,可使用其餘替代方案。

gRPC 容許你定義四類服務方法:

  • 單項 RPC,即客戶端發送一個請求給服務端,從服務端獲取一個應答,就像一次普通的函數調用。
  • 服務端流式 RPC,即客戶端發送一個請求給服務端,可獲取一個數據流用來讀取一系列消息。客戶端從返回的數據流裏一直讀取直到沒有更多消息爲止。
  • 客戶端流式 RPC,即客戶端用提供的一個數據流寫入併發送一系列消息給服務端。一旦客戶端完成消息寫入,就等待服務端讀取這些消息並返回應答。
  • 雙向流式 RPC,即兩邊均可以分別經過一個讀寫數據流來發送一系列消息。這兩個數據流操做是相互獨立的,因此客戶端和服務端能按其但願的任意順序讀寫,例如:服務端能夠在寫應答前等待全部的客戶端消息,或者它能夠先讀一個消息再寫一個消息,或者是讀寫相結合的其餘方式。每一個數據流裏消息的順序會被保持。

使用 API 接口

gRPC 提供 protocol buffer 編譯插件,可以從一個服務定義的 .proto 文件生成客戶端和服務端代碼。一般 gRPC 用戶能夠在服務端實現這些API,並從客戶端調用它們。

  • 在服務側,服務端實現服務接口,運行一個 gRPC 服務器來處理客戶端調用。gRPC 底層架構會解碼傳入的請求,執行服務方法,編碼服務應答。
  • 在客戶側,客戶端有一個存根實現了服務端一樣的方法。客戶端能夠在本地存根調用這些方法,用合適的 protocol buffer 消息類型封裝這些參數— gRPC 來負責發送請求給服務端並返回服務端 protocol buffer 響應。

同步 vs 異步

同步 RPC 調用一直會阻塞直到從服務端得到一個應答,這與 RPC 但願的抽象最爲接近。另外一方面網絡內部是異步的,而且在許多場景下可以在不阻塞當前線程的狀況下啓動 RPC 是很是有用的。

在多數語言裏,gRPC 編程接口同時支持同步和異步的特色。你能夠從每一個語言教程和參考文檔裏找到更多內容(很快就會有完整文檔)。

 

 

RPC 生命週期

 

單項 RPC

首先咱們來了解一下最簡單的 RPC 形式:客戶端發出單個請求,得到單個響應。

  • 一旦客戶端經過樁調用一個方法,服務端會獲得相關通知 ,通知包括客戶端的元數據,方法名,容許的響應期限(若是能夠的話)
  • 服務端既能夠在任何響應以前直接發送回初始的元數據,也能夠等待客戶端的請求信息,到底哪一個先發生,取決於具體的應用。
  • 一旦服務端得到客戶端的請求信息,就會作所需的任何工做來建立或組裝對應的響應。若是成功的話,這個響應會和包含狀態碼以及可選的狀態信息等狀態明細及可選的追蹤信息返回給客戶端 。
  • 假如狀態是 OK 的話,客戶端會獲得應答,這將結束客戶端的調用。

服務端流式 RPC

服務端流式 RPC 除了在獲得客戶端請求信息後發送回一個應答流以外,與咱們的簡單例子同樣。在發送完全部應答後,服務端的狀態詳情(狀態碼和可選的狀態信息)和可選的跟蹤元數據被髮送回客戶端,以此來完成服務端的工做。客戶端在接收到全部服務端的應答後也完成了工做。

客戶端流式 RPC

客戶端流式 RPC 也基本與咱們的簡單例子同樣,區別在於客戶端經過發送一個請求流給服務端,取代了原先發送的單個請求。服務端一般(但並沒必要須)會在接收到客戶端全部的請求後發送回一個應答,其中附帶有它的狀態詳情和可選的跟蹤數據。

雙向流式 RPC

雙向流式 RPC ,調用由客戶端調用方法來初始化,而服務端則接收到客戶端的元數據,方法名和截止時間。服務端能夠選擇發送回它的初始元數據或等待客戶端發送請求。 下一步怎樣發展取決於應用,由於客戶端和服務端能在任意順序上讀寫 - 這些流的操做是徹底獨立的。例如服務端能夠一直等直到它接收到全部客戶端的消息才寫應答,或者服務端和客戶端能夠像"乒乓球"同樣:服務端後獲得一個請求就回送一個應答,接着客戶端根據應答來發送另外一個請求,以此類推。

截止時間

gRPC 容許客戶端在調用一個遠程方法前指定一個最後期限值。這個值指定了在客戶端能夠等待服務端多長時間來應答,超過這個時間值 RPC 將結束並返回DEADLINE_EXCEEDED錯誤。在服務端能夠查詢這個期限值來看是否一個特定的方法已通過期,或者還剩多長時間來完成這個方法。 各語言來指定一個截止時間的方式是不一樣的 - 好比在 Python 裏一個截止時間值老是必須的,但並非全部語言都有一個默認的截止時間。

RPC 終止

在 gRPC 裏,客戶端和服務端對調用成功的判斷是獨立的、本地的,他們的結論可能不一致。這意味着,好比你有一個 RPC 在服務端成功結束("我已經返回了全部應答!"),到那時在客戶端多是失敗的("應答在最後期限後纔來到!")。也可能在客戶端把全部請求發送完前,服務端卻判斷調用已經完成了。

取消 RPC

不管客戶端仍是服務端都可以再任什麼時候間取消一個 RPC 。一個取消會當即終止 RPC 這樣能夠避免更多操做被執行。它不是一個"撤銷", 在取消前已經完成的不會被回滾。固然,經過同步調用的 RPC 不能被取消,由於直到 RPC 結束前,程序控制權尚未交還給應用。

元數據集

元數據是一個特殊 RPC 調用對應的信息(受權詳情]) ,這些信息以鍵值對的形式存在,通常鍵的類型是字符串,值的類型通常也是字符串(固然也能夠是二進制數據)。元數據對 gRPC 本事來講是不透明的 - 它讓客戶端提供調用相關的信息給服務端,反之亦然。 對於元數據的訪問是語言相關的。

流控制

TBD

配置

TBD

頻道

在建立客戶端存根時,一個 gRPC 頻道提供一個特定主機和端口服務端的鏈接。客戶端能夠經過指定頻道參數來修改 gRPC 的默認行爲,好比打開關閉消息壓縮。一個頻道具備狀態,包含已鏈接空閒 。 gRPC 如何處理關閉頻道是語言相關的。有些語言可容許詢問頻道狀態。

 

安全認證

gRPC 被設計成能夠利用插件的形式支持多種受權機制。本文檔對多種支持的受權機制提供了一個概覽,而且用例子來論述對應API,最後就其擴展性做了討論。

 

支持的受權機制

SSL/TLS

gRP 集成 SSL/TLS 並對服務端受權所使用的 SSL/TLS 進行了改良,對客戶端和服務端交換的全部數據進行了加密。

對客戶端來說提供了可選的機制提供憑證來得到共同的受權。

OAuth 2.0

gRPC 提供通用的機制(後續進行描述)來對請求和應答附加基於元數據的憑證。

當經過 gRPC 訪問 Google API 時,會爲必定的受權流程提供額外的獲取訪問令牌的支持,這將經過如下代碼例子進行展現。 警告:Google OAuth2 憑證應該僅用於鏈接 Google 的服務。把 Google 對應的 OAuth2 令牌發往非 Google 的服務會致使令牌被竊取用做冒充客戶端來訪問 Google 的服務。

API

爲了減小複雜性和將混亂最小化, gRPC 以一個統一的憑證對象來進行工做。 憑證能夠是如下兩類:

  • 頻道憑證, 被附加在 頻道上, 好比 SSL 憑證。
  • 調用憑證, 被附加在調用上(或者 C++ 裏的 客戶端上下文)。
    • 憑證能夠用組合頻道憑證來進行組合。
    • 一個組合頻道憑證能夠將一個頻道憑證和一個調用憑證關聯建立一個新的頻道憑證
    • 結果在這個頻道上的每次調用會發送組合的調用憑證來做爲受權數據。
      •  例如,一各頻道憑證能夠由一個Ssl 憑證和一個訪問令牌憑證生成。結果是在這個頻道上的每次調用都會發送對應的訪問令牌。 調用憑證能夠用 組合憑證來組裝。組裝後的 調用憑證應用到一個客戶端上下文裏,將觸發發送這兩個調用憑證的受權數據。

 

通信協議

HTTP2 協議上的 gRPC

大綱

如下是 gRPC 請求和應答消息流中通常的消息順序:

  • 請求 → 請求報頭 *有定界符的消息 EOS
  • 應答 → 應答報頭 *有定界符的消息 EOS
  • 應答 → (應答報頭 *有定界符的消息 跟蹤信息) / 僅僅跟蹤時

請求

  • 請求 → 請求報頭 *界定的消息 EOS 請求報頭是經過報頭+聯繫幀方式以 HTTP2 報頭來發送的。

  • 請求報頭 → 調用定義 *自定義元數據

  • 調用定義 → 方法模式路徑TE [受權] [超時] [內容類型] [消息類型] [消息編碼] [接受消息類型] [用戶代理]

  • 方法 → 「:method POST」

  • 模式 → 「:scheme 」 (「http」 / 「https」)

  • 路徑 → 「:path」 {開放的 API 對應的方法路徑}

  • Authority → 「:authority」 {受權的對應的虛擬主機域名}

  • TE → 「te」 「trailers」 # 用來檢測不兼容的代理

  • 超時 → 「grpc-timeout」 超時時間值 超時時間單位

  • 超時時間值 → {至少8位數字正整數的 ASCII 碼字符串}

  • 超時時間單位 → 時 / 分 / 秒 / 毫秒 / 微秒 / 納秒

  • → 「H」

  • → 「M」

  • → 「S」

  • 毫秒 → 「m」

  • 微秒 → 「u」

  • 納秒 → 「n」

  • 內容類型 → 「content-type」 「application/grpc」 [(「+proto」 / 「+json」 / {自定義})]

  • 內容編碼 → 「gzip」 / 「deflate」 / 「snappy」 / {自定義}

  • 消息編碼 → 「grpc-encoding」 Content-Coding

  • 接受消息編碼 → 「grpc-accept-encoding」 Content-Coding *("," Content-Coding)

  • 用戶代理 → 「user-agent」 {結構化的用戶代理字符串}

  • 消息類型 → 「grpc-message-type」 {消息模式的類型名}

  • 自定義數據 → 二進制報頭 / ASCII 碼報頭

  • 二進制報頭 → {以「-bin」結尾小寫的報頭名稱的 ASCII 碼 } {以 base64 進行編碼的值}

  • ASCII 碼報頭 → {小寫報頭名稱的 ASCII 碼} {}

界定的消息的重複序列經過數據幀來進行傳輸。

  • 界定的消息 → 壓縮標誌 消息長度 消息

  • 壓縮標誌 → 0 / 1 # 編碼爲 1 byte 的無符號整數

  • 消息長度 → {消息長度} # 編碼爲 4 byte 的無符號整數

  • 消息 → *{二進制字節}

應答

  • 應答 → (應答報頭 界定的消息 跟蹤信息) / 僅僅跟蹤

  • 應答報頭 → HTTP 狀態 [消息編碼] [消息接受編碼] 內容類型 *自定義元數據

  • 僅僅跟蹤 → HTTP 狀態 內容類型 跟蹤消息

  • 跟蹤消息 → 狀態 [狀態消息] *自定義元數據

  • HTTP狀態 → 「:status 200」

  • 狀態 → 「grpc-status」 <狀態碼的 ASCII 字符串>

  • 狀態消息 → 「grpc-message」 <狀態描述文本對應的 ASCII 字符串>

HTTP2 傳輸映射

流識別

全部的 GRPC 調用須要定義指定一個內部 ID。咱們將在這個模式裏使用 HTTP2 流 ID 來做爲調用標識。注意:這些 ID 在一個打開的 HTTP2 會話裏是先後關聯的,在一個處理多個 HTTP2 會話的進程裏不是惟一的,也不能被用做 GUID。

數據幀

數據幀邊界與界定消息的邊界無關,實現時不該假定它們有一致性。

錯誤

當應用錯誤或運行時錯誤在 PRC 調用過程當中出現時,狀態狀態消息應當經過跟蹤消息發送。

安全

HTTP2 規範當使用 TLS 時強制使用 TLS 1.2 及以上的版本,而且在部署上對容許的密碼施加一些額外的限制以免已知的好比須要 SNI 支持的問題。而且期待 HTTP2 與專有的傳輸安全機制相結合,這些傳輸機制的規格說明不能提供有意義的建議。

鏈接管理

GOAWAY 幀

服務端發出這種幀給客戶端表示服務端在相關的鏈接上再也不接受任何新流。這種幀包含服務端最後成功接受的流的ID。客戶端應該認爲任何在最後成功的流後面初始化的任意流爲 UNAVAILABLE,而且在別處重試這些調用。客戶端能夠自由地在已經接受的流上繼續工做直到它們完成或者鏈接中斷。 服務端應該在終止鏈接前發送 GOAWAY 幀,以可靠地通知客戶端哪些工做已經被服務端接受並執行。

PING 幀

客戶端和服務端都可以發送一個 PING 幀,對方必須精確回顯它們所接收到的信息。這能夠被用來確認鏈接仍然是活動的,而且可以提供估計端對端延遲估計的方法。假如服務端初始的 PING 在最後期限仍然沒有收到運行時所期待的應答的話,全部未完成的調用將會被以取消狀態關閉。一個客戶端期滿的初始的PING則會致使全部的調用被以用不可用狀態關閉。注意PING的頻率高度依賴於網絡環境,實現能夠根據網絡和應用須要,自由地調整PING頻率。

鏈接失敗

假如客戶端檢測到鏈接失敗,全部的調用都會被以不可用狀態關閉。而服務端側則全部已經打開的調用都會被以取消狀態關閉。

 

  • 服務端流式 RPC,即客戶端發送一個請求給服務端,可獲取一個數據流用來讀取一系列消息。客戶端從返回的數據流裏一直讀取直到沒有更多消息爲止。
相關文章
相關標籤/搜索