开箱即用的的go-zero框架(下)| 青训营

338 阅读4分钟

本章介绍rpc服务,并且在go-zero框架中运用rpc服务,api调用rpc服务,让读者更加理解rpc服务是什么东西

rpc服务介绍

RPC(Remote procedure Call)远程过程调用,是一种进程间通信方式,允许程序调用另一个地址空间的过程或函数,而不用了解底层通信细节。

RPC的主要流程是:

  1. 客户端通过 Stub 提供的接口调用服务端的方法。
  2. Stub将方法参数备份成请求数据,通过网络发送给服务端。
  3. 服务端的Skeleton接收请求数据,找到相应的方法处理。
  4. 服务端方法执行结果返回给Skeleton。
  5. 骨架将返回结果发送给客户端。
  6. Client Stub 接收结果,解包迁移调用方。

RPC的优点:

  • 隐藏了底层的通信细节,对用户透明
  • 客户端调用方式类似调用本地服务,简单便捷
  • 可传输复杂的构造数据
  • 面向服务,符合现代设计理念

RPC的缺点:

  • 开销大,需要序列化和网络开销
  • 不如消息队列灵活
  • 调试和测试不方便

在go-zero中使用rpc服务

rpc 服务

编写 proto 文件

  • 生成 user.proto 文件

使用命令 goctl rpc template -o user.proto, 生成 user.proto 文件

  • user.proto 文件的作用

user.proto 的作用是用来生成 rpc 服务的相关代码。

protobuf 的语法已经超出了 go-zero 的范畴了,这里就不详细展开了。

  • 编写 user.proto 文件

鉴于文章篇幅考虑完整的 user.proto 文件请参考 gitee 上的仓库。

生成 rpc 相关代码

  • 生成 user rpc 服务相关代码

使用命令 goctl rpc proto -src user.proto -dir . 生成 user rpc 服务的代码。

小结

rpc 服务相关命令:

  • 使用命令 goctl rpc template -o user.proto, 生成 user.proto 文件
  • 使用命令 goctl rpc proto -src user.proto -dir . 生成 user rpc 服务的代码。

api 服务调用 rpc 服务

A:为什么本节要安排在 rpc 服务的后面?

Q:因为 logic 部分的内容主体就是调用对应的 user rpc 服务,所以我们必须要在 user rpc 的代码已经生成后才能开始这部分的内容。

A:api 网关层调用 rpc 服务的步骤

Q:对这部分目录结构不清楚的,可以参考前文 “api 网关层-api 相关代码-目录介绍”。

  • 编辑配置文件 etc/blog-api.yaml,配置 rpc 服务的相关信息。

Name: blog-api
Host: 0.0.0.0
Port: 8888
# 新增 user rpc 服务.
User:
  Etcd:
#  Hosts 是 user.rpc 服务在 etcd 中的 value 值  
    Hosts:
      - localhost:2379
# Key 是 user.rpc 服务在 etcd 中的 key 值
    Key: user.rpc
  • 编辑文件 config/config.go

type Config struct {
   rest.RestConf
   // 手动添加
   // RpcClientConf 是 rpc 客户端的配置, 用来解析在 blog-api.yaml 中的配置
   User zrpc.RpcClientConf
}
  • 编辑文件 internal/svc/servicecontext.go
type ServiceContext struct {
   Config config.Config
   // 手动添加
   // users.Users 是 user rpc 服务对外暴露的接口
   User   users.Users
}

func NewServiceContext(c config.Config) *ServiceContext {
   return &ServiceContext{
      Config: c,
      // 手动添加
      //  zrpc.MustNewClient(c.User) 创建了一个 grpc 客户端
      User:   users.NewUsers(zrpc.MustNewClient(c.User)),
   }
}
  • 编辑各个 logic 文件,这里以 internal/logic/loginlogic.go 为例
func (l *LoginLogic) Login(req types.ReqUser) (*types.RespLogin, error) {
   // 调用 user rpc 的 login 方法
   resp, err := l.svcCtx.User.Login(l.ctx, &users.ReqUser{Username: req.Username, Password: req.Password})
   if err != nil {
      return nil, err
   }
   return &types.RespLogin{Token: resp.Token}, nil
}

rpc 调用 model 层的代码

rpc 目录结构

rpc 服务我们只需要关注下面加注释的文件或目录即可。


├── etc
│   └── user.yaml # 配置文件,数据库的配置写在这
├── internal
│   ├── config
│   │   └── config.go # config.go 是 yaml 对应的结构体
│   ├── logic # 填充业务逻辑的地方
│   │   ├── createlogic.go
│   │   ├── deletelogic.go
│   │   ├── getalllogic.go
│   │   ├── getlogic.go
│   │   ├── loginlogic.go
│   │   └── updatelogic.go
│   ├── server
│   │   └── usersserver.go
│   └── svc
│       └── servicecontext.go # 封装各种依赖
├── user
│   └── user.pb.go
├── user.go
├── user.proto
└── users
    └── users.go

rpc 调用 model 层代码的步骤

  • 编辑 etc/user.yaml 文件
Name: user.rpc
ListenOn: 127.0.0.1:8080
Etcd:
  Hosts:
  - 127.0.0.1:2379
  Key: user.rpc
# 以下为手动添加的配置
# mysql 配置
DataSource: root:1234@tcp(localhost:3306)/gozero
# 对应的表
Table: user
# redis 作为换存储
Cache:
  - Host: localhost:6379
  • 编辑 internal/config/config.go 文件
type Config struct {
// zrpc.RpcServerConf 表明继承了 rpc 服务端的配置
   zrpc.RpcServerConf
   DataSource string          // 手动代码
   Cache      cache.CacheConf // 手动代码
}
  • 编辑 internal/svc/servicecontext.go, 把 model 等依赖封装起来。

type ServiceContext struct {
   Config config.Config
   Model  model.UserModel // 手动代码
}

func NewServiceContext(c config.Config) *ServiceContext {
   return &ServiceContext{
      Config: c,
      Model:  model.NewUserModel(sqlx.NewMysql(c.DataSource), c.Cache), // 手动代码
   }
}

然后就可以编写业务了。

小结

go-zero中使用RPC调用的主要方式如下:

  1. 定义proto文件,指定服务接口和消息结构。
  2. 使用protoc-gen-go生成pb.go文件。
  3. 服务端实现pb.go中的接口。
  4. 客户端初始化rpc客户端,调用接口方法。
  5. Stub负责请求序列化备份发送。
  6. Server端处理请求并返回。
  7. Client端接收响应并解包。

go-zero使用grpc实现了RPC框架:

  • zrpc提供了抽象的RPC接口。
  • znet实现了grpc的传输层。
  • service/rpc实现了服务端的grpc Server。
  • client/grpc 实现了客户端的grpc Client。

go-zero的RPC调用隐藏了底层网络和序列化,最简单,可以快速构建RPC服务。

主要优点:

  • 接口通过协议文件一致定义
  • 自动生成客户端和服务器端代码
  • 简单的调用方式
  • 服务发现和负载均衡
  • 超时和重试机制

通过go-zero的RPC框架,可以方便地实现微服务间的远程调用。