【轉載】gRPC學習筆記

原文連接: https://zhuanlan.zhihu.com/p/...

rpc框架概述

微服務架構是近期比較流行的架構,知乎也實現了服務化。要實現服務化,則首先要解決各個服務之間的通訊問題。那麼就會面臨數據序列化、反序列化、鏈接管理、收發線程、超時處理等問題。若是本身實現一套這樣的機制,不但重複勞動,性能和效率也難以保證。rpc框架的出現解決了這些問題,讓調用者沒必要關心底層細節。目前主流的rpc框架有Apache Thrift、gRPC、Netty等。Apache Thrift和gRPC都是跨語言的rpc框架,他們採用了IDL來描述數據類型和接口,使用編譯器編譯出特定語言的代碼從而實現跨語言的rpc。本文主要介紹gRPC的規範及實現。html

gRPC實現

rpc框架通常基於tcp或者http協議實現。基於http的rpc框架有許多優勢,HTTP/1.x協議簡單明瞭,是目前最流行的應用層協議,有着很是成熟且完善的各類基礎設施,如負載均衡、監控、代理等,適用性普遍,各個設備系統均有實現。可是缺點也很明顯,就是HTTP/1.x採用的是文本協議,解析速度慢,帶寬佔用高。並且request/response的通訊方法致使總體效率不高。gRPC基於HTTP2協議,HTTP2 使得grpc 可以更好的適用於移動客戶端和服務端通訊的使用場景,而且鏈接多路複用也保證了RPC 的效率。grpc 的協議設計上很好的使用了HTTP2 現有的語義,請求和響應的數據使用HTTP Body 發送,其餘的控制信息則用Header 表示。nginx

HTTP2基本概念git

流(Stream)github

流是服務器和客戶端在HTTP/2鏈接內用於交換幀數據的獨立雙向序列,邏輯上可看作一個較爲完整的交互處理單元,即表達一次完整的資源請求-響應數據交換流程;一個業務處理單元,在一個流內進行處理完畢,這個流生命週期完結。web

特色以下:算法

  • 一個HTTP/2鏈接可同時保持多個打開的流,任一端點交換幀
  • 客戶端、服務端雙方均可以創建流,流也能夠被任意一方關閉
  • 流的標識符天然數表示,1~2^31-1區間,有建立流的終端分配
  • 客戶端發起的流使用奇數流ID,服務端發起的使用偶數,ID爲0、1的流保留
  • HTTP/2鏈接上傳輸的每一個幀都關聯到一個流,一個鏈接上能夠同時有多個流
  • 同一個流的幀按序傳輸,不一樣流的幀交錯混合傳輸

幀(Frame)chrome

HTTP/2拋棄HTTP/1的文本協議改成二進制協議,HTTP2的基本傳輸單元爲幀,每一個幀都從屬於某個流。json

幀的格式以下:api

  • - Length: Payload 長度
  • - Type: 幀類型
  • - Stream identifier:所屬流ID
  • - Frame Payload: 依幀類型而不一樣

幀的類型有:瀏覽器

  • - HEADERS 對應HTTP/1的 Headers
  • - DATA 對應HTTP/1的 Body
  • - CONTINUATION 頭部太大,分多個幀傳輸(一個HEADERS+若干CONTINUATION)
  • - SETTINGS 鏈接設置
  • - WINDOW_UPDATE 流量控制
  • - PUSH_PROMISE 服務端推送
  • - PRIORITY 流優先級更改
  • - PING 心跳或計算RTT
  • - RST_STREAM 立刻停止一個流
  • - GOAWAY 關閉鏈接而且發送錯誤信息

流是爲了實現多路復而提出的邏輯概念,在一個鏈接上能夠同時存在多個流。而流是由一個個的幀組成,在一個流裏面的幀是有序的,多個流之間的幀能夠混雜在一塊兒傳輸。

gRPC over HTTP2

gRPC在HTTP2的基礎上定義了request和response的規範。使用header幀描述meta信息如超時時間、payload的壓縮算法等等。使用data幀傳輸具體的rpc參數和返回結果。

request header

scheme: http或者https

method: 固定爲POST

path: 服務名/rpc方法名

content-type: 目前取值都是application/grpc+proto,或json或其餘自定義協議

grpc-encoding 能夠有gzip, deflate, snappy 等取值,表示採用的壓縮方法。

grpc-timeout 表示調用的超時時間,單位有Hour(H), Minute(M), Second(S), Millisecond(m), Microsecond(u), Nanosecond(n) 等。

response header

response有兩種,通常狀況下response都要包含有header幀、數據幀和trailer。若是服務端發生了錯誤,則能夠只返回一個trailer即 Trailers-Only 。

Response-Headers 主要包括 HTTP-Status,Content-Type 以及 Custom-Metadata 等。Trailers-Only 也有 HTTP-Status ,Content-Type 和 Trailers。Trailers 包括了 Status 以及 0 或者多個 Custom-Metadata。

HTTP-Status 就是咱們一般的 HTTP 200,301,400 這些,很通用就再也不解釋。Status 也就是 gRPC 的 status, 而 Status-Message 則是 gRPC 的 message。Status-Message 採用了 Percent-Encoded 的編碼方式,具體參考這裏

若是在最後收到的 HEADERS frame 裏面,帶上了 Trailers,而且有 END_STREAM 這個 flag,那麼就意味着 response 的 EOS。

Request例子:

HEADERS (flags = END_HEADERS)
:method = POST
:scheme = http
:path = /google.pubsub.v2.PublisherService/CreateTopic
:authority = pubsub.googleapis.com
grpc-timeout = 1S
content-type = application/grpc+proto
grpc-encoding = gzip
authorization = Bearer y235.wef315yfh138vh31hv93hv8h3v

DATA (flags = END_STREAM)
<Delimited Message>

Response例子:

HEADERS (flags = END_HEADERS)
:status = 200
grpc-encoding = gzip

DATA
<Delimited Message>

HEADERS (flags = END_STREAM, END_HEADERS)
grpc-status = 0 # OK
trace-proto-bin = jher831yy13JHy3hc

從圖中能夠看出,客戶端的每次rpc調用都發起了一個流,而後在這個流中發送header幀和數據幀,而服務端的返回結過結果也是使用同一個流進行傳輸。

雖然說gRPC使用HTTP/2協議,不少瀏覽器也開始支持HTTP2,可是目前還不能使用瀏覽器做爲客戶端訪問gRPC服務。由於gRPC的response在數據幀以後還有一個trailer header幀(這個幀內包含了grpc-status和grpc-message頭),這會致使chrome的崩潰。爲了解決這一問題一個新項目grpc-web正在開發之中,還處於early access階段,參見這裏。grpc-web在grpc over HTTP2的基礎上修改和新增了一些規範,使得可以經過瀏覽器和JavaScript調用gRPC服務,參見這裏

Nginx目前也沒法代理gRPC服務。雖然nginx從1.9.5版本開始支持HTTP2,可是還不支持反向代理HTTP2的upstreaming。參見這裏

目前可行的經過瀏覽器訪問grpc的方法是使用一個gateway,在grpc服務和瀏覽器之間做爲中介,接受瀏覽器的Restful請求轉換成grpc標準的請求發送到服務端。參見這個項目

相關文章
相關標籤/搜索