2022-10-04 分類: 網(wǎng)站建設
介紹
我猜測大部分長期使用 Java 的開發(fā)者應該較少會接觸 gRPC,畢竟在 Java 圈子里大部分使用的還是 Dubbo/SpringClound 這兩類服務框架。
我也是近段時間有機會從零開始重構業(yè)務才接觸到 gRPC 的,當時選擇gRPC 時也有幾個原因:
基于云原生的思路開發(fā)部署項目,而在云原生中 gRPC 幾乎已經(jīng)是標準的通訊協(xié)議了。 開發(fā)語言選擇了 Go,在 Go 圈子中 gRPC 顯然是更好的選擇。 公司內部有部分業(yè)務使用的是 Python 開發(fā),在多語言兼容性上 gRPC 支持的非常好。
經(jīng)過線上一年多的平穩(wěn)運行,可以看出 gRPC 還是非常穩(wěn)定高效的;rpc 框架中最核心的幾個要點:序列化 通信協(xié)議 IDL(接口描述語言)
這些在 gRPC 中分別對應的是: 基于 Protocol Buffer 序列化協(xié)議,性能高效。 基于 HTTP/2 標準協(xié)議開發(fā),自帶 stream、多路復用等特性;同時由于是標準協(xié)議,第三方工具的兼容性會更好(比如負載均衡、監(jiān)控等)。編寫一份 .proto 接口文件,便可生成常用語言代碼。 HTTP/2
學習 gRPC 之前首先得知道它是通過什么協(xié)議通信的,我們日常不管是開發(fā)還是應用基本上接觸到最多的還是 HTTP/1.1 協(xié)議。
由于 HTTP/1.1 是一個文本協(xié)議,對人類非常友好,相反的對機器性能就比較低。
需要反復對文本進行解析,效率自然就低了;要對機器更友好就得采用二進制,HTTP/2 自然做到了。
除此之外還有其他優(yōu)點: 多路復用:可以并行的收發(fā)消息,互不影響。HPACK 節(jié)省 header 空間,避免 HTTP1.1 對相同的 header 反復發(fā)送。 Protocol
gRPC 采用的是 Protocol 序列化,發(fā)布時間比 gRPC 早一些,所以也不僅只用于 gRPC,任何需要序列化 IO 操作的場景都可以使用它。
它會更加的省空間、高性能;之前在開發(fā) https://github.com/crossoverJie/cim 時就使用它來做數(shù)據(jù)交互。package order.v1; service OrderService{ rpc Create(OrderApiCreate) returns (Order) {} rpc Close(CloseApiCreate) returns (Order) {} // 服務端推送 rpc ServerStream(OrderApiCreate) returns (stream Order) {} // 客戶端推送 rpc ClientStream(stream OrderApiCreate) returns (Order) {} // 雙向推送 rpc BdStream(stream OrderApiCreate) returns (stream Order) {} } message OrderApiCreate{ int64 order_id = 1; repeated int64 user_id = 2; string remark = 3; repeated int32 reason_id = 4; }使用起來也是非常簡單的,只需要定義自己的 .proto 文件,便可用命令行工具生成對應語言的 SDK。
具體可以參考官方文檔:https://grpc.io/docs/languages/go/generated-code/ 調用 protoc --go_out=. --go_opt=paths=source_relative \ --go-grpc_out=. --go-grpc_opt=paths=source_relative \ test.proto 生成代碼之后編寫服務端就非常簡單了,只需要實現(xiàn)生成的接口即可。func (o *Order) Create(ctx context.Context, in *v1.OrderApiCreate) (*v1.Order, error) { // 獲取 metadata md, ok := metadata.FromIncomingContext(ctx) if !ok { return nil, status.Errorf(codes.DataLoss, "failed to get metadata") } fmt.Println(md) fmt.Println(in.OrderId) return &v1.Order{ OrderId: in.OrderId, Reason: nil, }, nil }客戶端也非常簡單,只需要依賴服務端代碼,創(chuàng)建一個 connection 然后就和調用本地方法一樣了。
這是經(jīng)典的 unary(一元)調用,類似于 http 的請求響應模式,一個請求對應一次響應。
Server stream
gRPC 除了常規(guī)的 unary 調用之外還支持服務端推送,在一些特定場景下還是很有用的。
func (o *Order) ServerStream(in *v1.OrderApiCreate, rs v1.OrderService_ServerStreamServer) error { for i := 0; i < 5; i++ { rs.Send(&v1.Order{ OrderId: in.OrderId, Reason: nil, }) } return nil } 服務端的推送如上所示,調用 Send 函數(shù)便可向客戶端推送。 for { msg, err := rpc.RecvMsg() if err == io.EOF { marshalIndent, _ := json.MarshalIndent(msgs, "", "\t") fmt.Println(msg) return } }客戶端則通過一個循環(huán)判斷當前接收到的數(shù)據(jù)包是否已經(jīng)截止來獲取服務端消息。
為了能更直觀的展示這個過程,優(yōu)化了之前開發(fā)的一個 gRPC 客戶端,可以直觀的調試 stream 調用。
上圖便是一個服務端推送示例。Client Stream
除了支持服務端推送之外,客戶端也支持。
客戶端在同一個連接中一直向服務端發(fā)送數(shù)據(jù),服務端可以并行處理消息。// 服務端代碼func (o *Order) ClientStream(rs v1.OrderService_ClientStreamServer) error { var value []int64 for { recv, err := rs.Recv() if err == io.EOF { rs.SendAndClose(&v1.Order{ OrderId: 100, Reason: nil, }) log.Println(value) return nil } value = append(value, recv.OrderId) log.Printf("ClientStream receiv msg %v", recv.OrderId) } log.Println("ClientStream finish") return nil } // 客戶端代碼 for i := 0; i < 5; i++ { messages, _ := GetMsg(data) rpc.SendMsg(messages[0]) } receive, err := rpc.CloseAndReceive()代碼與服務端推送類似,只是角色互換了。
Bidirectional Stream
同理,當客戶端、服務端同時都在發(fā)送消息也是支持的。// 服務端func (o *Order) BdStream(rs v1.OrderService_BdStreamServer) error { var value []int64 for { recv, err := rs.Recv() if err == io.EOF { log.Println(value) return nil } if err != nil { panic(err) } value = append(value, recv.OrderId) log.Printf("BdStream receiv msg %v", recv.OrderId)
分享名稱:五分鐘學會gRPC,你學會了嗎?
鏈接分享:http://jinyejixie.com/news28/201728.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供響應式網(wǎng)站、動態(tài)網(wǎng)站、手機網(wǎng)站建設、電子商務、服務器托管、建站公司
聲明:本網(wǎng)站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內容