Golang 語言編寫 gRPC 實戰項目

大家好,我是 frank。
歡迎大家點擊標題下方藍色文字「Golang 語言開發棧」關注公衆號。
設爲星標,第一時間接收推送文章。
文末掃碼,大家一起學 Golang 語言。

**01 **

介紹

在之前的幾篇文章中,我們介紹了 protobuf 和 grpc,本文我們介紹怎麼使用 grpc 開發 “分佈式系統”。這裏使用引號是因爲分佈式系統是一個大概念,本文我們先介紹使用 grpc 開發分佈式系統中的 service。

grpc 是 google 開源的 rpc 框架,使用 grpc 可以方便開發 rpc service;protobuf 是一種接口設計語言(IDL),grpc 框架使用的 IDL 是 protobuf。如果有讀者朋友還不瞭解 protobuf 和 grpc,建議先翻閱之前的幾篇文章。

本文是介紹使用 grpc 開發一個實戰項目 - ToDoList,目標是幫助讀者朋友們熟悉項目開發流程,該實戰項目包含 server service 和 client service。server 主要負責數據操作,client 主要負責業務邏輯處理。

02

server

首先,我們創建 proto 目錄,並創建 proto 文件,編寫 protobuf,設計項目的 service,接着創建 pb 目錄,使用 protoc 編譯我們編寫好的 proto 文件,生成 pb 文件。然後,我們創建 service 目錄,編寫生成的 pb 文件中接口定義的方法。最後,我們創建 grpc 服務器。

server 目錄

.
├── dao
│   ├── mysql.go
│   └── toDoList.go
├── main.go
├── pb
│   ├── todoPb
│   │   ├── toDoList.pb.go
│   │   └── toDoList_grpc.pb.go
│   └── userPb
│       ├── user.pb.go
│       └── user_grpc.pb.go
├── proto
│   ├── toDoList.proto
│   └── user.proto
└── service
    └── toDoList.go

編寫 proto 文件

讀者朋友們如果還不熟悉 protobuf,建議翻閱之前介紹 protobuf 的文章,限於篇幅,本文不再贅述。示例代碼如下:

syntax = "proto3";

option go_package = "./todoPb";

service ToDoList {
  rpc CreateToDoList (ToDoListDetail) returns (CreateToDoListResult) {}
  rpc ReadToDoList (ToDoListPage) returns (ReadToDoListByPage) {}
}

message ToDoListDetail {
  // @inject_tag: form:"id" xorm:"'id' not null pk autoincr"
  int64 id = 1;

...

完整代碼,請查閱 github。

生成 pb 文件

接着,我們使用 protoc 編譯 proto 文件,生成 pb 文件,關於怎麼使用 protoc 編譯 proto 文件,在之前的文章已經詳細介紹,限於篇幅,本文不再贅述,編譯命令如下:

protoc --go_out=./pb --go-grpc_out=./pb proto/* && protoc-go-inject-tag -XXX_skip=xorm -input=./pb/todoPb/toDoList.pb.go

執行以上命令,將在 pb 目錄中自動生成 pb 文件。

編寫接口定義的方法

至此,我們開始編寫 golang 代碼,在 service 目錄中創建 go 文件,實現生成的 pb 文件中接口定義的方法。

...

type ToDoList struct {
 pb.UnimplementedToDoListServer
}

func (t *ToDoList) CreateToDoList(ctx context.Context, in *pb.ToDoListDetail) (*pb.CreateToDoListResult, error) {
 log.Printf("id: %d content:%v datetime:%d\n", in.GetId(), in.GetContent(), in.GetDatetime())
 record, err := dao.Add(ctx, in)
 data := &pb.CreateToDoListResult{Record: record}
 return data, err
}

...

閱讀上面這段代碼,可以發現我們把數據庫操作相關代碼設計在 dao 包中。service 中通過調用 dao 包的方法操作數據庫,另外,其他數據操作組件也可以在 service 中調用。

完整代碼,請查閱 github。

創建 gRPC 服務器

在完成 service 代碼編寫之後,我們創建 grpc server,然後註冊服務。

...

server := grpc.NewServer()
 pb.RegisterToDoListServer(server, new(service.ToDoList))

...

完整代碼,請查閱 github。

以上就是使用 grpc 創建 rpc service 的一般流程,在生產環境項目中,還需要完善一些公共方法,比如配置文件讀取、錯誤碼定義、參數驗證等。爲了讀者朋友們容易理解,該實戰項目中未涉及這部分內容,感興趣的讀者朋友們可以嘗試自己實現該部分內容。

03

client

client 主要負責業務邏輯,本文介紹的實戰項目使用 gin 框架實現路由。通常,client service 的 pb 文件拷貝 server service 生成的 pb 文件。

首先,我們創建 controller 目錄,調用 server service 的方法,然後,使用 gin 框架設計路由。

client 目錄

.
├── controller
│   └── toDoList.go
├── main.go
├── pb
│   ├── todoPb
│   │   ├── toDoList.pb.go
│   │   └── toDoList_grpc.pb.go
│   └── userPb
│       ├── user.pb.go
│       └── user_grpc.pb.go
└── router
    └── router.go

拷貝 server service 生成的 pb 文件

client 直接拷貝 server service 生成的 pb 文件,不需要編寫 proto 文件,然後使用 protoc 編譯 proto 文件,生成 pb 文件。

編寫 controller 代碼,調用 server service 的方法

在 controller 目錄中創建 go 文件,編寫 controller 方法,並創建客戶端,使用創建的客戶端調用 server service 的方法。

func CreateToDoList(ctx *gin.Context) {

...

cc := NewToDoListClient()
 defer func() {
  err := cc.Close()
  if err != nil {
   log.Fatalf("conn close error=%v", err)
  }
 }()
 cli := pb.NewToDoListClient(cc)
 ctx1, cancel := context.WithTimeout(context.Background(), time.Second)
 defer cancel()
 res, err := cli.CreateToDoList(ctx1, param)
  
...

完整代碼,請查閱 github。

創建 gin 路由

編寫完 controller 之後,創建 router 目錄,在 router 目錄中創建 gin 路由,用於訪問 controller 中的方法。

...

r := gin.Default()
 apiV1 := r.Group("/v1")
 todolist := apiV1.Group("/todolist")
 {
  todolist.POST("/add", controller.CreateToDoList)

...

完整代碼,請查閱 github。

04

總結

本文我們介紹了怎麼使用 grpc 開發 service。讀者朋友們閱讀完本文,可以瞭解使用 grpc 開發 service 的一般開發流程,建議感興趣的讀者朋友們,實現項目中 user service 的代碼編寫。

參考資料:
https://developers.google.com/protocol-buffers/docs/proto3 
https://grpc.io/docs/languages/go/quickstart/ 
https://gin-gonic.com/ 
https://gobook.io/read/gitea.com/xorm/manual-zh-CN/

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/P317uoG-unNR_tZywVUFTg