前言
什麼是RPC服務 RPC,是Remote Procedure Call的簡稱,翻譯成中文就是遠端過程調用。RPC就是允許程式調用另一個位址空間(通常是另一台機器上)的類方法或函數的一種服務。 它是一種架設在計算機網絡之上并隐藏底層網絡技術,可以像調用本地服務一樣調用遠端程式,在編碼代價不高的情況下提升吞吐的能力。
為什麼要使用RPC服務 随着計算機技術的快速發展,單台機器運作服務的方案已經不足以支撐越來越多的網絡請求負載,分布式方案開始興起,一個業務場景可以被拆分在多個機器上運作,每個機器分别隻完成一個或幾個的業務子產品。為了能讓其他機器使用某台機器中的業務子產品方法,就有了RPC服務,它是基于一種專門實作遠端方法調用的協定上完成的服務。現如今很多主流語言都支援RPC服務,常用的有Java的Dubbo、Go的net/rpc & RPCX、谷歌的gRPC等。
關于gRPC 大部分RPC都是基于socket實作的,可以比http請求來的高效。gRPC是谷歌開發并開源的一款實作RPC服務的高性能架構,它是基于http2.0協定的,目前已經支援C、C++、Java、Node.js、Python、Ruby、Objective-C、PHP和C#等等語言。要将方法調用以及調用參數,響應參數等在兩個伺服器之間進行傳輸,就需要将這些參數序列化,gRPC采用的是protocol buffer的文法(檢查proto),通過proto文法可以定義好要調用的方法、和參數以及響應格式,可以很友善地完成遠端方法調用,而且非常利于擴充和更新參數。

快速上手gRPC
使用gRPC實作遠端方法調用之前,我們需要了解protocol buffer文法,安裝支援protocol buffer文法編譯成.proto檔案的工具,然後再完成gRPC的服務端(遠端方法提供者)和用戶端(調用者)的搭建和封裝。
Protocol Buffer是Google的跨語言,跨平台,可擴充機制的,用于序列化結構化資料 - 對比XML,但更小,更快,更簡單的一種資料格式。您可以定義資料的結構化,例如方法的名字、參數和響應格式等,然後可以使用對應的語言工具生成的源代碼輕松地在各種資料流中使用各種語言編寫和讀取結構化資料。
定義消息類型
上面的例子就是一個.proto檔案,該檔案的第一行指定包名,友善您在别的proto檔案中import這個檔案的定義,第二行是您正在使用proto3文法:如果您不這樣做,protobuf 編譯器将假定您正在使用proto2。這必須是檔案的第一個非空的非注釋行,目前建議使用proto3文法。 SearchRequest是消息體的名字,指定了三個字段,分别指定了字段的類型和順序,順序必須從1開始,并且不可重複;
指定字段規則 消息字段可以是以下之一:
單數(預設):格式良好的消息可以包含該字段中的零個或一個(但不超過一個)。 repeated:此字段可以在格式良好的消息中重複任意次數(包括零)。将保留重複值的順序。例如:
上述例子其實就是定義了一個格式,用我們通常的json格式表示就是:
标量值類型 标量消息字段可以具有以下類型之一 - 該表顯示.proto檔案中指定的類型,以及自動生成的類中的相應類型:
<col>
.proto Type
備注
Python Typ
double
float
int32
使用變長編碼,對于負值的效率很低,如果你的域有可能有負值,請使用sint64替代
int
uint32
使用變長編碼
int/long
uint64
sint32
使用變長編碼,這些編碼在負值時比int32高效的多
sint64
使用變長編碼,有符号的整型值。編碼時比通常的int64高效。
fixed32
總是4個位元組,如果數值總是比總是比228大的話,這個類型會比uint32高效。
fixed64
總是8個位元組,如果數值總是比總是比256大的話,這個類型會比uint64高效。
sfixed32
總是4個位元組
sfixed64
總是8個位元組
bool
布爾值
string
一個字元串必須是UTF-8編碼或者7-bit ASCII編碼的文本。
str/unicode
bytes
可能包含任意順序的位元組資料。
str
預設值 解析消息時,如果編碼消息不包含特定的單數元素,則解析對象中的相應字段将設定為該字段的預設值。這些預設值是特定于類型的:
對于字元串,預設值為空字元串。
對于位元組,預設值為空位元組。
對于bools,預設值為false。
對于數字類型,預設值為零。
對于枚舉,預設值是第一個定義的枚舉值,該值必須為0。
重複字段的預設值為空(通常是相應語言的空清單)
枚舉類型
Corpus枚舉的第一個常量映射為零:每個枚舉定義必須包含一個映射到零的常量作為其第一個元素。這是因為:
必須有一個零值,以便我們可以使用0作為數字預設值。
零值必須是第一個元素,以便與proto2語義相容,其中第一個枚舉值始終是預設值。
定義方法
上面的語句就定義好了遠端調用的方法名Search,待編譯好對應語言的源代碼之後就可以使用遠端調用,例如在Python中初始化SearchService方法,則執行Search方法,就是采用SearchRequest的格式去調用遠端機器的方法,然後按定義好的SearchResponse格式傳回調用結果。根據proto的文法定義,甚至可以實作跨平台,跨語言使用這種遠端調用。
根據實際工作需要,生成以下對應語言的自定義消息類型Java,Python,C ++,Go, Ruby, Objective-C,或C#的.proto檔案,你需要運作protobuf 編譯器protoc上.proto。如果尚未安裝編譯器,請下載下傳該軟體包并按照自述檔案中的說明進行操作。 Protobuf 編譯器的調用如下:
Python生成對應的源代碼
安裝Python的gRPC源碼包grpcio,用于執行gRPC的各種底層協定和請求響應方法
安裝Python基于gRPC的proto生成python源代碼的工具grpcio-tools
執行編譯生成python的proto序列化協定源代碼:
編譯後生成的源代碼:
test_pb2.py: 用來和 protobuf 資料進行互動,這個就是根據proto檔案定義好的資料結構類型生成的python化的資料結構檔案
test_pb2_grpc.py: 用來和 grpc 進行互動,這個就是定義了rpc方法的類,包含了類的請求參數和響應等等,可用python直接執行個體化調用
生成好了python可以直接執行個體化和調用的gRPC類,我們就可以開始搭建RPC的服務端(遠端調用提供者)和用戶端(調用者)了。
搭建服務端server.py
搭建用戶端client.py
最佳實踐
編寫proto檔案的時候,注意定義好資料的格式,要多考慮可擴張性,例如可以定義api_version等用于區分版本,防止未來的版本有大的資料格式更新的時候可以相容;
對于不可變類型,建議使用枚舉,例如請求一個字段type,取值是固定的時候,可以用枚舉類型;
對于服務端和用戶端的編寫,建議指定好最大接收和發送大小,避免出現資料溢出的異常;
gRPC偶爾會出現斷線重連的情況,是以要增加異常處理機制,捕獲到由于重連時引發遠端調用失敗的問題,則可以執行重試(會在接下來的文章中詳細說明);
gRPC可以采用SSL或TLS的協定,實作http2.0加密傳輸,提高系統的安全性(會在接下來的文章中詳細說明);
對于流量、并發較大的服務,可以通過微服務的一些應用或元件(如istio)等實作流量的熔斷、限流等等,提高穩定性。
gRPC的優勢
gRPC消息使用一種有效的二進制消息格式protobuf進行序列化。Protobuf在伺服器和客戶機上的序列化非常快。Protobuf序列化後的消息體積很小,能夠有效負載,在移動應用程式等有限帶寬場景中顯得很重要。
gRPC是為HTTP/2而設計的,它是HTTP的一個主要版本,與HTTP 1.x相比具有顯著的性能優勢:
二進制架構和壓縮。HTTP/2協定在發送和接收方面都很緊湊和高效。
通過單個TCP連接配接複用多個HTTP/2調用。多路複用消除了線頭阻塞。
所有gRPC架構都為代碼生成提供了一流的支援。gRPC開發的核心檔案是*.proto檔案 ,它定義了gRPC服務和消息的約定。根據這個檔案,gRPC架構将生成服務基類,消息和完整的用戶端代碼。
通過在伺服器和用戶端之間共享*.proto檔案,可以從端到端生成消息和用戶端代碼。用戶端的代碼生成消除了用戶端和伺服器上的重複消息,并為您建立了一個強類型的用戶端。無需編寫用戶端代碼,可在具有許多服務的應用程式中節省大量開發時間。
不存在具有JSON的HTTP API的正式規範。開發人員不需要讨論URL,HTTP動詞和響應代碼的最佳格式。(想想,是用Post還是Get好?使用Get還是用Put好?一想到有選擇恐懼症的你是不是又開了糾結,然後浪費了大量的時間)
該gRPC規範是規定有關gRPC服務必須遵循的格式。gRPC消除了争論并節省了開發人員的時間,因為gPRC在各個平台和實作之間是一緻的。
HTTP/2為長期的實時通信流提供了基礎。gRPC通過HTTP/2為流媒體提供一流的支援。
gRPC服務支援所有流組合:
一進制(沒有流媒體)
伺服器到用戶端流
用戶端到伺服器流
雙向流媒體 截至時間/逾時和取消 gRPC允許用戶端指定他們願意等待RPC完成的時間。該期限被發送到服務端,服務端可以決定在超出了限期時采取什麼行動。例如,伺服器可能會在逾時時取消正在進行的gRPC / HTTP /資料庫請求。
通過子gRPC調用截至時間和取消操作有助于實施資源使用限制。
微服務 - gRPC設計為低延遲和高吞吐量通信。gRPC非常适用于效率至關重要的輕型微服務。 點對點實時通信 - gRPC對雙向流媒體提供出色的支援。gRPC服務可以實時推送消息而無需輪詢。 多語言混合開發環境 - gRPC工具支援所有流行的開發語言,使gRPC成為多語言開發環境的理想選擇。
網絡受限環境 - 使用Protobuf(一種輕量級消息格式)序列化gRPC消息。gRPC消息始終小于等效的JSON消息。