[gRPC] gRPC Getting Started
gRPC 說明影片 @ BESG
對應的程式碼可檢視 besg-grpc 的 repository。
gRPC 是什麼:以 Golang 說明與實作
RPC 的全名是 remote procedure call,主要是作為電腦和電腦間溝通使用。A 電腦可以呼叫 B 電腦執行某些程式,B 電腦會將結果回傳給 A 電腦,A 電腦在收到回應後會再繼續處理其他任務。RPC 的好處在於,雖然 A 電腦是發送請求去請 B 電腦做事,但其呼叫的方式,就很像是 A 電腦直接在呼叫自己內部的函式一般。
gRPC 也是基於這樣的概念,讓想要呼叫 server 處理請求的 client,在使用這支 API 時就好像是呼叫自己內部的函式一樣簡單自然。從功能面來說,gRPC 就像 Web 常用的 Restful API 一樣,都是在處理請求和回應,並且進行資料交換,但 gRPC 還多了其他的功能和特色。
gRPC 是由 Google 開發的開源框架,它快速有效、奠基在 HTTP/2 上提供低延遲(low latency),支援串流,更容易做到權限驗證(authentication)。在下面的文章中,將會對於 gRPC 能提供的特色有更多說明。
Protocol Buffers 是什麼
- Protocol Buffers @ Google Developer
- Protocol Buffers 筆記 @ pjchender.dev
在學習 gRPC 時,需要同時了解什麼是 Protocol Buffers。在傳統的 Restful API 中,最常使用的資料交換格式通常是 JSON;但到了 gRPC 中,資料交換的格式則是使用名為 Protocol Buffers 的規範/語言。
也就是說,當我們想要使用 gRPC 的服務來交換資料前,必須先把資料「格式」和「方法」都定義清楚。
使用 gRPC 前,不只需要先把資料交換的格式定義清楚,同時也需要把資料交換的方法定義清楚。
這裡要稍微釐清一點很重要的是,Protocol Buffers 可以獨立使用,不一定要搭配 gRPC;但使用 gRPC 一定要搭配 Protocol Buffers。
實作將 Protocol Buffers 編譯成在 Golang 中可使用的檔案
對應的程式碼可檢視 besg-grpc repository 中的 proto 資料夾。
STEP 1:撰寫 Protocol Buffers 檔案
- 使用
message
定義資料交換的格式 - 使用
service
定義呼叫 API 的方法名稱
syntax = "proto3"; // 定義要使用的 protocol buffer 版本
package calculator; // for name space
option go_package = "proto/calculator"; // generated code 的 full Go import path
message CalculatorRequest {
int64 a = 1;
int64 b = 2;
}
message CalculatorResponse {
int64 result = 1;
}
service CalculatorService {
rpc Sum(CalculatorRequest) returns (CalculatorResponse) {};
}
STEP 2:安裝編譯 Protocol Buffer 所需的套件
此部份可參考 編譯 Protocol Buffers(Compiling) 段落。
安裝 compiler
# 安裝 compiler,安裝完後就會有 protoc CLI 工具
$ brew install protobuf
$ protoc --version # Ensure compiler version is 3+
# 安裝 protoc-gen-go 後可以將 proto buffer 編譯成 Golang 可使用的檔案
$ go get github.com/golang/protobuf/protoc-gen-go
# 安裝 grpc-go 後,可以在 Golang 中使用 gRPC
$ go get -u google.golang.org/grpc
STEP 3:編譯 Protocol Buffer 檔案
進到放有 .proto
檔的資料夾後,在終端機輸入下述指令:
$ protoc *.proto --go_out=plugins=grpc:. --go_opt=paths=source_relative
在成功編譯好後,應該會看到同樣的資料夾位置出現 *.pb.go
的檔案,這就是編譯好後可以在 Golang 中使用 Protocol Buffer 和 gRPC 的檔案。
實作 gRPC Server
對應的程式碼可檢視 besg-grpc repository 中的 server 資料夾。
STEP 1:建立 gRPC server
type Server struct {}
func main() {
fmt.Println("starting gRPC server...")
lis, err := net.Listen("tcp", "localhost:50051")
if err != nil {
log.Fatalf("failed to listen: %v \n", err)
}
grpcServer := grpc.NewServer()
calculatorPB.RegisterCalculatorServiceServer(grpcServer, &Server{})
if err := grpcServer.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v \n", err)
}
}
STEP 2:實作 Protocol Buffer 中的 service
func (*Server) Sum(ctx context.Context, req *calculatorPB.CalculatorRequest) (*calculatorPB.CalculatorResponse, error) {
fmt.Printf("Sum function is invoked with %v \n", req)
a := req.GetA()
b := req.GetB()
res := &calculatorPB.CalculatorResponse{
Result: a + b,
}
return res, nil
}
STEP 3:啟動 server
在終端機中輸入:
$ go run server/server.go
即可啟動 gRPC server。
補充:使用 Bloom RPC 進行測試
在只有 server 的情況下,可以使用BloomRPC 這套工具來模擬 Client 對 gRPC server 發送請求,功能就類似在 Restful 中使用的 Postman。
使用時只需要匯入 proto 檔後,即可看到對應可呼叫的方法和可帶入的參數,能這麼方便也是因為在 protocol buffer 中已經把傳輸的資料格式和能對應呼叫的方法都定好的緣故。
建立 gRPC Client
完整程式碼可檢視 besg-grpc repository 中的 client 資料夾。
STEP 1:與 gRPC server 建立連線
func main() {
conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
if err != nil {
log.Fatalf("failed to dial: %v", err)
}
defer conn.Close()
client := calculatorPB.NewCalculatorServiceClient(conn)
doUnary(client)
}