Golang 语言编写 gRPC 实战项目

简介: Golang 语言编写 gRPC 实战项目

介绍

在之前的几篇文章中,我们介绍了 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 主要负责业务逻辑处理。

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 的代码编写。

推荐阅读:

Golang 语言怎么处理错误?

参考资料:

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/ 

目录
相关文章
|
2月前
|
Go
Golang语言之管道channel快速入门篇
这篇文章是关于Go语言中管道(channel)的快速入门教程,涵盖了管道的基本使用、有缓冲和无缓冲管道的区别、管道的关闭、遍历、协程和管道的协同工作、单向通道的使用以及select多路复用的详细案例和解释。
110 4
Golang语言之管道channel快速入门篇
|
2月前
|
Go
Golang语言文件操作快速入门篇
这篇文章是关于Go语言文件操作快速入门的教程,涵盖了文件的读取、写入、复制操作以及使用标准库中的ioutil、bufio、os等包进行文件操作的详细案例。
66 4
Golang语言文件操作快速入门篇
|
2月前
|
Go
Golang语言之gRPC程序设计示例
这篇文章是关于Golang语言使用gRPC进行程序设计的详细教程,涵盖了RPC协议的介绍、gRPC环境的搭建、Protocol Buffers的使用、gRPC服务的编写和通信示例。
101 3
Golang语言之gRPC程序设计示例
|
2月前
|
安全 Go
Golang语言goroutine协程并发安全及锁机制
这篇文章是关于Go语言中多协程操作同一数据问题、互斥锁Mutex和读写互斥锁RWMutex的详细介绍及使用案例,涵盖了如何使用这些同步原语来解决并发访问共享资源时的数据安全问题。
86 4
|
2月前
|
Go 调度
Golang语言goroutine协程篇
这篇文章是关于Go语言goroutine协程的详细教程,涵盖了并发编程的常见术语、goroutine的创建和调度、使用sync.WaitGroup控制协程退出以及如何通过GOMAXPROCS设置程序并发时占用的CPU逻辑核心数。
50 4
Golang语言goroutine协程篇
|
2月前
|
Prometheus Cloud Native Go
Golang语言之Prometheus的日志模块使用案例
这篇文章是关于如何在Golang语言项目中使用Prometheus的日志模块的案例,包括源代码编写、编译和测试步骤。
51 3
Golang语言之Prometheus的日志模块使用案例
|
1月前
|
前端开发 中间件 Go
实践Golang语言N层应用架构
【10月更文挑战第2天】本文介绍了如何在Go语言中使用Gin框架实现N层体系结构,借鉴了J2EE平台的多层分布式应用程序模型。文章首先概述了N层体系结构的基本概念,接着详细列出了Go语言中对应的构件名称,包括前端框架(如Vue.js、React)、Gin的处理函数和中间件、依赖注入和配置管理、会话管理和ORM库(如gorm或ent)。最后,提供了具体的代码示例,展示了如何实现HTTP请求处理、会话管理和数据库操作。
30 0
|
2月前
|
Go
Golang语言错误处理机制
这篇文章是关于Golang语言错误处理机制的教程,介绍了使用defer结合recover捕获错误、基于errors.New自定义错误以及使用panic抛出自定义错误的方法。
46 3
|
2月前
|
Go
Golang语言之函数(func)进阶篇
这篇文章是关于Golang语言中函数高级用法的教程,涵盖了初始化函数、匿名函数、闭包函数、高阶函数、defer关键字以及系统函数的使用和案例。
58 3
Golang语言之函数(func)进阶篇
|
2月前
|
Go
Golang语言之函数(func)基础篇
这篇文章深入讲解了Golang语言中函数的定义和使用,包括函数的引入原因、使用细节、定义语法,并通过多个案例展示了如何定义不返回任何参数、返回一个或多个参数、返回值命名、可变参数的函数,同时探讨了函数默认值传递、指针传递、函数作为变量和参数、自定义数据类型以及返回值为切片类型的函数。
59 2
Golang语言之函数(func)基础篇