背景
在如今雲原生技術的大環境下,rpc服務作爲最重要的互聯網技術,蓬勃發展,誕生了許多知名基於rpc協議的框架,其中就有本文的主角gRPC技術。
一款高性能、開源的通用rpc框架
作者作爲一名在JD實習的Cpper,經過一段時間的學習和實踐,發現了C++與Java之間的種種不同,這也讓我產生了一個想法:既然rpc需要做到的就是客戶端無感知調用,那麼客戶端和服務端使用的語言也不應該成爲約束,正巧在來JD實習之前,我就有接觸過gRPC,所以就想寫一篇文章分析一下gRPC與當今主流rpc框架之間的區別與優勢。
對比
1. gRPC的實現原理
在 gRPC 裏客戶端應用可以像調用本地對象一樣直接調用另一臺不同的機器上服務端應用的方法,使得使用者能夠更容易地創建分佈式應用和服務。與許多 RPC 系統類似,gRPC 也是基於以下理念:定義一個服務,指定其能夠被遠程調用的方法(包含參數和返回類型)。在服務端實現這個接口,並運行一個 gRPC 服務器來處理客戶端調用。在客戶端擁有一個存根能夠像服務端一樣的方法。
gRPC的客戶端和服務端可以用在多樣化的環境中運行,使用者可以使用各種官方支持的語言來構建自己的應用。例如:你可以很輕易的使用Java作爲gRPC的服務端,而在客戶端使用Ruby、Go、Python等語言。
gRPC調用圖
2. gRPC的優勢與劣勢
2.1 優勢:
2.1.1 多語言支持
gRPC官方就支持多種編程語言,包括C#/.NET, C++, Dart, Go, Java, Kotlin, Node.js, Objective-C, PHP, Python, Ruby等。開發人員無需考慮使用何種開發語言,可以充分利用語言的優勢:C++的內存操作,go語言的靈活,Java的生態豐富......
2.1.2 基於Protocol Buffers
gRPC默認使用Protocol Buffers作爲其接口定義語言(IDL)和底層消息交換格式。Protocol Buffers是一種語言和平臺中立的接口描述語言,允許開發者定義數據結構和服務接口,並且可以生成多種語言的代碼。這使得在不同語言之間實現數據和服務接口的一致性變得簡單。其消息格式採用二進制方式傳輸,比傳統的Json體積更小。
具體的語法定義如下:
1. 消息定義:在 .proto 文件中定義消息,消息由字段組成。字段有三種類型:required、optional、repeated,分別表示必須、可選和重複。
message Person {
required string name = 1;
optional int32 id = 2;
repeated string email = 3;
}
2. 枚舉定義:枚舉類型允許你定義一組有限的可能的值。
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
3. 服務定義:服務允許你定義一組相互關聯的RPC(遠程過程調用)。
service HelloService {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
4.字段編號:每個字段都有一個唯一的數字編號。這是必要的,因爲在解析過程中,我們需要知道每個字段的順序。在 .proto 文件中定義的每個字段都有默認值。例如,int32 類型的字段默認值爲 0。
5.字段類型:每個字段都有一個類型。例如,string、int32、message 等。對於 message 類型的字段,你需要在括號內定義該消息的類型。對於 repeated 類型的字段,你可以將多個值放入一個列表中。例如,Person 消息中的 email 字段可以包含一個電子郵件地址列表。
6.服務調用:在客戶端代碼中,你可以使用生成的 stub 類來調用服務方法。例如,你可以這樣調用 SayHello 方法:
HelloService.stub stub = HelloServiceGrpc.newBlockingStub(channel);
HelloReply response = stub.sayHello(HelloRequest.newBuilder().build());
2.1.3 跨平臺兼容性
gRPC支持多種軟件和硬件平臺。這種跨平臺能力意味着gRPC不僅能在不同的操作系統上運行,還能在各種環境中有效運行,如服務器、移動設備和Web環境。
2.1.4 底層調用協議
gRPC使用HTTP/2作爲底層傳輸協議克服了一些HTTP/1.1版本的一些限制。二進制組幀和壓縮。 HTTP/2 協議在發送和接收方面均緊湊且高效。在單個 TCP 連接上多路複用多個 HTTP/2 調用。 多路複用可消除隊頭阻塞。
2.1.5 強大的社區和生態系統
gRPC的社區和生態系統提供了豐富的文檔、教程和API參考,幫助開發者在不同的語言和平臺上使用gRPC。這種廣泛的社區支持也促進了對新語言和平臺的支持。例如:Dubbo3對gRPC的支持、gRPC-Swift、gRPC-Spring。
github上的gRPC生態支持
2.1.6 嚴格規範
具有 JSON 的 HTTP API 沒有正式規範。 開發人員爲 URL、HTTP 謂詞和響應代碼的最佳格式爭論不休。gRPC 規範對 gRPC 服務必須遵循的格式進行了規定。 gRPC 消除了爭論併爲開發人員節省了時間,因爲 gRPC 在各個平臺和實現中都是一致的。
2.2 劣勢:
2.2.1 瀏覽器支持有限
當下,不可能直接從瀏覽器調用gRPC服務。gRPC大量使用HTTP/2功能,沒有瀏覽器提供支持gRPC客戶機的Web請求所需的控制級別。例如,瀏覽器不允許調用者要求使用的HTTP/2,或者提供對底層HTTP/2框架的訪問。
2.2.2 不是人類可讀的
HTTP API請求以文本形式發送,可以由人讀取和創建。默認情況下,gRPC消息使用protobuf編碼。**雖然protobuf的發送和接收效率很高,但它的二進制格式是不可讀的8。protobuf需要在.proto文件中指定的消息接口描述才能正確反序列化。需要額外的工具來分析線路上的Protobuf有效負載,並手工編寫請求。
grpc與傳統rpc相比較
3. demo展示
下面作者將使用C++與go作爲開發語言來展示gRPC強大的跨語言調用能力
項目結構:
grpc-demo
├── cpp
│ ├── CMakeLists.txt // C++的CMakeLists.txt文件,用來生成makefile
│ ├── cmake // 用來存放一些cmake函數
│ │ └── common.cmake // cmake函數
│ ├── include // 頭文件
│ ├── proto // Protocol Buffers定義文件
│ │ └── helloworld.proto
│ └── src // C++源文件
│ └── main.cpp
├── go
│ ├── Makefile // makefile腳本
│ ├── go.mod // Go語言包管理
│ ├── proto
│ │ ├── helloworld.proto
│ ├── service
│ └── src // go源文件
│ └── main
│ └── main.go
└── proto
└── helloworld.proto
項目源代碼: https://github.com/ConstantineQAQ/grpc-demo
總結
迴歸題目,gRPC因爲他強大的可擴展性,輕便的底層傳輸格式,越來越多的企業在技術選型時選擇了它,我也希望未來能有一款應用可以通過gRPC發揮出每種語言的優勢,綻放出絢麗的色彩。