一、簡介
我們在前面學習了thrift rpc的知識,我們從其中接觸到了IDL,編解碼協議,服務的遠程調用(調用遠程服務就像在在本地調用一樣)等各種概念。
其實我個人對thrift的使用并不多,我更多的是使用今天我們要提到的一個RPC框架稱之為gRPC,其實作為一個rpc框架,grpc和之前提到的thrift是有很多相似之處的,包括他也有IDL這個概念。只是語法不一樣而已。
但是作為一個非常流行的rpc框架,grpc是有自己的獨到設計的,下面我們來看看他的一些特點和概念。
1. gRPC 是由google開源的一個高性能的RPC框架。是由Google內部的Stubby RPC,演化而來的,2015正式開源。在如今大行其道的云原生時代,實際上它已經是一個事實上的RPC標準。2. gRPC 核心的設計思路 1. 網絡通信: gRPC自己封裝網絡通信的部分 提供多種語言的 網絡通信的封裝 (C Java[Netty] GO),所以他也是有多語言異構的能力的。他也是通過IDL來實現語言無關的翻譯能力。2. 協議:使用HTTP2作為網絡傳輸協議,傳輸數據的時候數據體使用二進制數據內容。 支持雙向流(雙工)連接的多路復用。3. 序列化:較之于傳統的http1的基本文本JSON格式,http2是基于二進制內容序列化的。具體的話,他是使用了一種叫做protobuf (Protocol Buffers) 的序列化方式,這是google開源一種序列化方式,時間效率和空間效率是JSON的3---5倍。IDL語言 4. 代理的創建 :讓調用者像調用本地方法那樣 去調用遠端的服務方法。我們可以看到,上面四點,其實只需要我們處理3,使用protobuf來定義IDL,實現序列化,數據消息翻譯成目標語言。其余的grpc都封裝好了給我們。3. gRPC 與 ThriftRPC 區別共性:支持異構語言的RPC。區別:1. 網絡通信 Thrift 的第五層是自己定義的專屬協議,而GRPC則是選擇了HTTP22. 性能角度 ThriftRPC 性能 高于 gRPC,畢竟他是自己實現的協議,更加精準。3. gRPC 大廠背書(Google),云原生時代 與其他組件合作的順利。所以gRPC應用更廣泛,nacos中就有使用。4. gRPC的好處 1. 高效的進行進程間通信。2. 支持多種語言 原生支持 C Go Java實現。C語言版本上擴展 C++ C# NodeJS Python Ruby PHP..3. 支持多平臺運行 Linux Android IOS MacOS Windows。4. gPRC序列化方式采用protobuf,效率高。5. 使用Http2協議6. 大廠的背書(谷歌)
二、關于http2
實際上網上關于http2的內容已經很多了。我這里就不做太多的贅述了,我來簡單描述一下,如果有什么不足之處,大家多多指教。
1、Http1.x協議
1.1、http1.0
1、Http1.0協議時代,他是基于請求響應的模式,屬于一種短連接協議,也就是你發送請求接受相應之后就立刻斷開。所以他是無狀態的,無狀態的意思就是服務端不知道你客戶端是誰,因為你每次都斷開。但是實際上我們開發的時候往往需要記住狀態,所以大家設計了cookie和session的機制來記住,每次你帶著你的標記來。但是這機制畢竟不是網絡協議的內容,是技術人員的一種彌補技術手段。
2、他是傳輸數據文本結構,你可能會說有時候我上傳文件,明明傳的是二進制的,數據是二進制的,但是其余的請求頭,標記等等都是文本。
3、單工模式, 無法實現服務端主動推送,為了變相實現推送一般使用客戶端輪訓的方式,也就是客戶端不斷的去詢問,達到一種看似感知服務端的效果。但是大部分是空輪訓,浪費資源了。
1.2、http1.1
Http1.1協議依然是請求響應的模式,但是已經進化成為了一種有限的長連接,通過keepalive請求頭標識來保持一段時間的長連接,而且可以通過 升級的方式實現WebSocket 的雙工協議,進而實現服務器向客戶端推送。
Http1.x協議 共性
1. 傳輸數據文本格式,可讀性好的但是效率差。
2. 本質上Http1.x協議無法實現雙工通信。
3. 資源的請求。比如我們要像服務器請求三個資源,就需要發送三次請求,建立多個連接才可以完成。(有時候你發接口請求,需要請求一些靜態資源,就要多次請求獲取)
2. HTTP2.0協議
1. Http2.0協議是一個二進制協議,效率高于Http1.x協議,可讀性差。2. 可以實現雙工通信。3. 一個請求 一個連接 可以請求多個數據。【多路復用】# Http2.0協議的三個概念1. 數據流 stream2. 消息 message3. 幀 frame 參看圖
# 其他的相關概念
1. 數據流的優先級,可以通過為不同的stream設置權重,來限制不同流的傳輸順序。
2. 流控 client發送的數據太快了,server處理不過來,通知client暫停數據的發送。
我們來畫一個圖來表示一下http2的這些概念。
我們看到它把以前我們需要建立三次連接獲取三次數據的格式變成了,建立一次連接,通過流的形式發送過去,然后響應回來。而且這個還可以調整stream之間的權重來選擇先響應哪個后響應哪個。
三、Protocol Buffers [protobuf]
1. protobuf 是一種與編程語言無關【IDL】,與具體的平臺無關【OS】。他定義的中間語言,可以方便的在client 于 server中進行RPC的數據傳輸。
2. protobuf 兩種版本 proto2 proto3,但是目前主流應用的都是proto3。
3. protobuf主要安裝protobuf的編譯器,編譯器目的,可以把protobuf的IDL語言,轉換成具體某一種開發語言。
1、protobuf編譯器的安裝
下載地址:https://github.com/protocolbuffers/protobuf/releases
windows 版本1. 直接解壓縮 方式在一個特定的目錄下面2. 直接配置環境變量 path
mac版本brew install protobuf protoc --version 來檢驗是否安裝
2、protobuf IDEA的插件
1. 2021.2版本后面的新版本 IDEA內置了Protobuf插件
2. 之前版本 可以選裝第三方Protobuf插件
3. 二者不能共存。
3、protobuf的語法
其實官方提供了詳細的語法介紹,我們可以去參考一下protobuf的官方文檔
3.1、文件格式
所有的proto內容都要寫在.proto后綴的文件中。比如
UserService.proto
OrderService.proto
3.2、版本設定
syntax = “proto3”;
文件最上面聲明出版本號。
3.3、注釋
1. 單行注釋 //
2. 多行注釋 /* */
3.4、與Java語言相關的語法
#后續protobuf生成的java代碼 一個源文件還是多個源文件 xx.java,自己開發一般一個簡單,有時候實際開發會按照業務拆分多個組織,看要求。
option java_multiple_files = false; #指定protobuf生成的類 放置在哪個包中,java的包
option java_package = "com.levi";#指定的protobuf生成的外部類的名字(管理內部類【內部類才是真正開發使用】)
option java_outer_classname = "UserServce";
在protobuf中我們的這些業務類都是有一個外部類的,他的作用就是管理這些業務類。這就是他的規范。
option的意思就是可以選,所以以上這些你都可以不寫,有默認的。最好味了規范還是寫上。
3.5、邏輯包
這個用的不多,他的作用是用來管理多個proto文件,不是管理包劃分。而是一種proto的劃分,類似于這個proto屬于這個邏輯包下這種區分。用來結構管理。
# 對于protobuf對于文件內容的管理
package xxx;
3.6、導入
UserService.protoOrderService.protoimport "xxx/UserService.proto";
OrderService.proto導入了UserService.proto,就可以在OrderService.proto中使用UserService.proto中定義的內容了。
3.7、基本類型
類型中定義了proto文件中的proto類型和各個語言的基本類型的對應,可以看一下,我們這里主要觀察java即了。
3.8、枚舉類型
enum SEASON{SPRING = 0;SUMMER = 1;}
枚舉的值 必須是0開始 ,后面那個是標號,不一定連續,但是一定要從0開始遞增。
grpc的標號和thrift不一樣,他是放在=后面的。
3.9、消息 Message
其實就是實體類,thrift是struct那些,grpc直接就是message。
message LoginRequest {string username = 1;singular string password = 2;int32 age = 3;
}編號 從1開始 到2^29-1 注意:19000 - 19999 不能用這個區間內的編號,因為他是protobuf自己保留的。這個編號不需要連續,遞增就好了。# 一組關鍵字
- singular : 這個字段的值 只能是0個或1個 (默認關鍵字) null "123456"
- repeated :返回集合,proto會生成對應的getList方法。
message Result{string code = 200;repeated string datas = 2; //這個字段 返回值 是多個 比如我們分頁要獲取多個回來集合
}# 可以定義多個消息
message LoginRequest{....
}
message LoginResponse{...
}# 消息可以嵌套
message SearchResponse{message Result{string url = 1;string title = 2;}string xxx = 1;int32 yyy = 2;# 可以直接使用嵌套Result ppp = 3;
}message AAA{string xxx = 1;SearchResponse.Result yyy = 2; # 直接.引用內部即可
}# oneof [其中一個],標識這個類型的東西雖然里面有多個屬性,但是只會返回一個
message SimpleMessage{oneof test_oneof{string name = 1;int32 age = 2;}# test_oneof這個屬性只會返回name或者age一個。test_oneof xxx
}
3.10、服務service
就是service業務類。
service HelloService{rpc hello(HelloRequest) returns(HelloResponse){}
}
# 里面是可以定義多個服務方法。而且都是以rpc開頭。HelloRequest,HelloResponse這些類型都是我們之前定義的消息。后面的{}表示業務體,這里不寫內容,具體由你生成結構之后自己去寫。
# 定義多個服務接口
# gPRC 服務 4種服務方式,后續介紹 。