Trying Out go-zero Microservices

Reference address: https://go-zero.dev/cn/docs/quick-start/micro-service#%E5%88%9B%E5%BB%BAuser-rpc%E6%9C%8D%E5%8A%A1

Introduction to go-zero

go-zero (included in the CNCF Cloud Native Landscape: https://landscape.cncf.io/?selected=go-zero) is a web and rpc framework that integrates a variety of engineering practices. Through resilient design it guarantees the stability of highly concurrent server-side services and has been fully proven in practice.

go-zero includes a minimalist API definition and the generation tool goctl, which can generate Go, iOS, Android, Kotlin, Dart, TypeScript and JavaScript code from a defined api file with a single command, and the generated code can be run directly.

The benefits of using go-zero:

  • Easily obtain the stability to support a service with tens of millions of daily active users
  • Built-in microservice governance capabilities such as cascading timeout control, rate limiting, adaptive circuit breaking and adaptive load shedding, with no configuration or extra code required
  • Microservice governance middleware can be seamlessly integrated into other existing frameworks
  • A minimalist API description that generates code for every client with one command
  • Automatically validates the legality of client request parameters
  • A large number of microservice governance and concurrency toolkits
  1. Quickly create a microservice according to the official documentation
    We first create go-zero-demo in the go project directory

    mkdir go-zero-demo
    cd go-zero-demo
    go mod init go-zero-demo

  2. Create the user rpc service

2.1 Create the user rpc directory

 mkdir -p mall/user/rpc

2.2 Add the user.proto file and add a getUser method

vim mall/user/rpc/user.proto

2.3 Add the following code:

    syntax = "proto3";
    package user;
    // for protoc-gen-go versions greater than 1.4.0, the proto file needs go_package, otherwise it cannot be generated
    option go_package = "./user";
    message IdRequest {
        string id = 1;
    }
    message UserResponse {
      // user id
      string id = 1;
      // user name
      string name = 2;
      // user gender
      string gender = 3;
    }
    service User {
        rpc getUser(IdRequest) returns(UserResponse);
    }

2.4 Generate the code

  cd mall/user/rpc
  goctl rpc protoc user.proto --go_out=./types --go-grpc_out=./types --zrpc_out=.

2.5 Fill in the business logic

 vim internal/logic/getuserlogic.go


package logic
import (
  "context"
  "go-zero-demo/mall/user/rpc/internal/svc"
  "go-zero-demo/mall/user/rpc/types/user"
  "github.com/zeromicro/go-zero/core/logx"
)
type GetUserLogic struct {
  ctx context.Context
  svcCtx *svc.ServiceContext
  logx.Logger
}
func NewGetUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserLogic {
  return &GetUserLogic{
  ctx: ctx,
  svcCtx: svcCtx,
  Logger: logx.WithContext(ctx),
  }
}
func (l *GetUserLogic) GetUser(in *user.IdRequest) (*user.UserResponse, error) {
  return &user.UserResponse{
  Id: "1",    
  Name: "test",
  }, nil
}
  1. Create the order api service#

3.1 Create the order api directory

Go back to the go-zero-demo/mall directory

mkdir -p order/api && cd order/api

3.1 Add the api file

 vim order.api


type(
  OrderReq {
      Id string `path:"id"`
  }
  OrderReply {
      Id string `json:"id"`
      Name string `json:"name"`
  }
)
service order {
  @handler getOrder
  get /api/order/get/:id (OrderReq) returns (OrderReply)
}

3.2 Generate the order service

 goctl api go -api order.api -dir .

3.3 Add the user rpc configuration

 vim internal/config/config.go

Additional content

package config
import (
  "github.com/zeromicro/go-zero/zrpc"
  "github.com/zeromicro/go-zero/rest"
)

type Config struct {
  rest.RestConf
  UserRpc zrpc.RpcClientConf
}

3.4 Add the yaml configuration

 vim etc/order.yaml 


Name: order
Host: 0.0.0.0
Port: 8888
UserRpc:
Etcd:
Hosts:
- 127.0.0.1:2379
Key: user.rpc

3.5 Complete the service dependency
The official documentation uses user here, but when I used it locally I found that the generated code has no user, only userclient — it is very likely that the official documentation was not updated in time.

vim internal/svc/servicecontext.go

Additional content

package svc

import (

"go-zero-demo/mall/order/api/internal/config"
"go-zero-demo/mall/user/rpc/userclient"
"github.com/zeromicro/go-zero/zrpc"
)
type ServiceContext struct {
Config config.Config
UserRpc userclient.User
}
func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{
Config: c,
UserRpc: userclient.NewUser(zrpc.MustNewClient(c.UserRpc)),
}
}

3.6 Add business logic to getorderlogic

vim internal/logic/getorderlogic.go

Additional content

package logic
import (
  "context"
  "errors"
  "go-zero-demo/mall/order/api/internal/svc"
  "go-zero-demo/mall/order/api/internal/types"
  "go-zero-demo/mall/user/rpc/types/user"
  "github.com/zeromicro/go-zero/core/logx"
)

type GetOrderLogic struct {
  logx.Logger
  ctx context.Context
  svcCtx *svc.ServiceContext
}

func NewGetOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) GetOrderLogic {
    return GetOrderLogic{
    Logger: logx.WithContext(ctx),
    ctx: ctx,
    svcCtx: svcCtx,
    }
}

func (l *GetOrderLogic) GetOrder(req *types.OrderReq) (*types.OrderReply, error) {
    user, err := l.svcCtx.UserRpc.GetUser(l.ctx, &user.IdRequest{
    Id: "1",
    })

    if err != nil {
    return nil, err
    }
    if user.Name != "test" {
    return nil, errors.New("用户不存在")
    }

    return &types.OrderReply{
    Id: req.Id,
    Name: "test order",
    }, nil

}
  1. Start the services and verify#

4.1 Start etcd
There is no etcd service here, you need to install it yourself

 etcd

4.2 Download the dependencies

In the go-zero-demo directory

 go mod tidy

4.3 Start the user rpc

In the mall/user/rpc directory

 go run user.go -f etc/user.yaml

If the following error appears, it means etcd has not been started

4.4 Start the order api

In the mall/order/api directory

 go run order.go -f etc/order.yaml

4.5 Access the order api

 curl -i -X GET http://localhost:8888/api/order/get/1