rpc编写与调用

在一个大的系统中,多个子系统(服务)间必然存在数据传递,有数据传递就需要通信方式,你可以选择最简单的http进行通信,也可以选择rpc服务进行通信, 在go-zero,我们使用zrpc来进行服务间的通信,zrpc是基于grpc。

场景

在前面我们完善了对用户进行登录,用户查询图书等接口协议,但是用户在查询图书时没有做任何用户校验,如果当前用户是一个不存在的用户则我们不允许其查阅图书信息, 从上文信息我们可以得知,需要user服务提供一个方法来获取用户信息供search服务使用,因此我们就需要创建一个user rpc服务,并提供一个getUser方法。

rpc服务编写

  • 编译proto文件

    1. $ vim service/user/rpc/user.proto
    1. syntax = "proto3";
    2. package user;
    3. option go_package = "user";
    4. message IdReq{
    5. int64 id = 1;
    6. }
    7. message UserInfoReply{
    8. int64 id = 1;
    9. string name = 2;
    10. string number = 3;
    11. string gender = 4;
    12. }
    13. service user {
    14. rpc getUser(IdReq) returns(UserInfoReply);
    15. }
    • 生成rpc服务代码
      1. $ cd service/user/rpc
      2. $ goctl rpc proto -src user.proto -dir .

      [!TIPS] 如果安装的 protoc-gen-go 版大于1.4.0, proto文件建议加上go_package

  • 添加配置及完善yaml配置项

    1. $ vim service/user/rpc/internal/config/config.go
    1. type Config struct {
    2. zrpc.RpcServerConf
    3. Mysql struct {
    4. DataSource string
    5. }
    6. CacheRedis cache.CacheConf
    7. }
    1. $ vim /service/user/rpc/etc/user.yaml
    1. Name: user.rpc
    2. ListenOn: 127.0.0.1:8080
    3. Etcd:
    4. Hosts:
    5. - $etcdHost
    6. Key: user.rpc
    7. Mysql:
    8. DataSource: $user:$password@tcp($url)/$db?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai
    9. CacheRedis:
    10. - Host: $host
    11. Pass: $pass
    12. Type: node

    [!TIP] $user: mysql数据库user

    $password: mysql数据库密码

    $url: mysql数据库连接地址

    $db: mysql数据库db名称,即user表所在database

    $host: redis连接地址 格式:ip:port,如:127.0.0.1:6379

    $pass: redis密码

    $etcdHost: etcd连接地址,格式:ip:port,如: 127.0.0.1:2379

    更多配置信息,请参考rpc配置介绍

  • 添加资源依赖

    1. $ vim service/user/rpc/internal/svc/servicecontext.go
    1. type ServiceContext struct {
    2. Config config.Config
    3. UserModel model.UserModel
    4. }
    5. func NewServiceContext(c config.Config) *ServiceContext {
    6. conn := sqlx.NewMysql(c.Mysql.DataSource)
    7. return &ServiceContext{
    8. Config: c,
    9. UserModel: model.NewUserModel(conn, c.CacheRedis),
    10. }
    11. }
  • 添加rpc逻辑

    1. $ service/user/rpc/internal/logic/getuserlogic.go
    1. func (l *GetUserLogic) GetUser(in *user.IdReq) (*user.UserInfoReply, error) {
    2. one, err := l.svcCtx.UserModel.FindOne(in.Id)
    3. if err != nil {
    4. return nil, err
    5. }
    6. return &user.UserInfoReply{
    7. Id: one.Id,
    8. Name: one.Name,
    9. Number: one.Number,
    10. Gender: one.Gender,
    11. }, nil
    12. }

使用rpc

接下来我们在search服务中调用user rpc

  • 添加UserRpc配置及yaml配置项
    1. $ vim service/search/api/internal/config/config.go
    1. type Config struct {
    2. rest.RestConf
    3. Auth struct {
    4. AccessSecret string
    5. AccessExpire int64
    6. }
    7. UserRpc zrpc.RpcClientConf
    8. }
    1. $ vim service/search/api/etc/search-api.yaml
    1. Name: search-api
    2. Host: 0.0.0.0
    3. Port: 8889
    4. Auth:
    5. AccessSecret: $AccessSecret
    6. AccessExpire: $AccessExpire
    7. UserRpc:
    8. Etcd:
    9. Hosts:
    10. - $etcdHost
    11. Key: user.rpc

    [!TIP] $AccessSecret:这个值必须要和user api中声明的一致。

    $AccessExpire: 有效期

    $etcdHost: etcd连接地址

    etcd中的Key必须要和user rpc服务配置中Key一致

  • 添加依赖

    1. $ vim service/search/api/internal/svc/servicecontext.go
    1. type ServiceContext struct {
    2. Config config.Config
    3. Example rest.Middleware
    4. UserRpc userclient.User
    5. }
    6. func NewServiceContext(c config.Config) *ServiceContext {
    7. return &ServiceContext{
    8. Config: c,
    9. Example: middleware.NewExampleMiddleware().Handle,
    10. UserRpc: userclient.NewUser(zrpc.MustNewClient(c.UserRpc)),
    11. }
    12. }
  • 补充逻辑

    1. $ vim /service/search/api/internal/logic/searchlogic.go
    1. func (l *SearchLogic) Search(req types.SearchReq) (*types.SearchReply, error) {
    2. userIdNumber := json.Number(fmt.Sprintf("%v", l.ctx.Value("userId")))
    3. logx.Infof("userId: %s", userIdNumber)
    4. userId, err := userIdNumber.Int64()
    5. if err != nil {
    6. return nil, err
    7. }
    8. // 使用user rpc
    9. _, err = l.svcCtx.UserRpc.GetUser(l.ctx, &userclient.IdReq{
    10. Id: userId,
    11. })
    12. if err != nil {
    13. return nil, err
    14. }
    15. return &types.SearchReply{
    16. Name: req.Name,
    17. Count: 100,
    18. }, nil
    19. }

    启动并验证服务

  • 启动etcd、redis、mysql
  • 启动user rpc
    1. $ cd /service/user/rpc
    2. $ go run user.go -f etc/user.yaml
    1. Starting rpc server at 127.0.0.1:8080...
  • 启动search api

    1. $ cd service/search/api
    2. $ go run search.go -f etc/search-api.yaml
  • 验证服务

    1. $ curl -i -X GET \
    2. 'http://127.0.0.1:8889/search/do?name=%E8%A5%BF%E6%B8%B8%E8%AE%B0' \
    3. -H 'authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MTI4NjcwNzQsImlhdCI6MTYxMjc4MDY3NCwidXNlcklkIjoxfQ.JKa83g9BlEW84IiCXFGwP2aSd0xF3tMnxrOzVebbt80'
    1. HTTP/1.1 200 OK
    2. Content
    3. -Type: application/json
    4. Date: Tue, 09 Feb 2021 06:05:52 GMT
    5. Content-Length: 32
    6. {"name":"西游记","count":100}

猜你想看