[ 微服务项目流程解析[go-zero] ]


创建项目案例01的ucenter的grpc服务文件夹

一. 配置文件

1./etc/config.yaml文件名, 以及内容(安装和部署etcd服务发现)

Name: ucenter.rpc
ListenOn: 0.0.0.0:8081
Etcd:
  Hosts:
  - 42.193.152.252:2379
  Key: ucenter.rpc
  Token: tkn
DbMysql:
  Host: 47.120.55.99
  Port: 3306
  Username: root
  Password:  chenhaifeng
  Databases: go_netdisk
CacheRedis:
  Host: "47.120.55.99:6379"
  Pass: chenhaifeng
  Type: node

2.main.go文件内同步文件名

var configFile = flag.String("f", "etc/config.yaml", "the config file")

3.internal/config.go文件

package config

import (
    "github.com/zeromicro/go-zero/core/stores/redis"
    "github.com/zeromicro/go-zero/zrpc"
)

type Config struct {
    zrpc.RpcServerConf
    DbMysql MysqlConf
    CacheRedis redis.RedisConf
}

type MysqlConf struct {
    Host      string
    Port      int
    Username  string
    Password  string
    Databases string
}

type RedisConf struct {
    Host string
    Pass string
    Type string
}

4.internal/svc/service_context.go服务的上下文

package svc

import (
    "ucenter/internal/config"

    "github.com/zeromicro/go-zero/core/stores/redis"
)

type ServiceContext struct {
    Config config.Config
    Redis  redis.Redis
}

func NewServiceContext(c config.Config) *ServiceContext {
    rds := redis.MustNewRedis(c.CacheRedis)
    return &ServiceContext{
        Config: c,
        Redis:  *rds,
    }
}

5.服务主文件 internal/server/register_srever.go

package server

import (
    "context"

    "ucenter/internal/logic"
    "ucenter/internal/svc"
    "grpc-common/ucenter/types/register"
)

type RegisterServer struct {
    svcCtx *svc.ServiceContext
    register.UnimplementedRegisterServer
}

func NewRegisterServer(svcCtx *svc.ServiceContext) *RegisterServer {
    return &RegisterServer{
        svcCtx: svcCtx,
    }
}

// 定义一个 SayHello 一元 rpc 方法,请求体和响应体必填。
func (s *RegisterServer) RegisterByPhone(ctx context.Context, in *register.RegReq) (*register.RegRes, error) {
    l := logic.NewRegisterByLogic(ctx, s.svcCtx)
    return l.RegisterByPhone(in)
}
func (s *RegisterServer) SendCode(ctx context.Context, in *register.CodeReq) (*register.CodeRes, error) {
    l := logic.NewRegisterByLogic(ctx, s.svcCtx)
    return l.SendCode(in)
}

6.服务的接口文件 internal/logic/register_logic.go

package logic

import (
    "context"
    "mscoin/mscoin-common/tools"
    "time"

    "grpc-common/ucenter/types/register"
    "ucenter/internal/svc"

    "github.com/zeromicro/go-zero/core/logx"
)

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

func NewRegisterByLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RegisterByLogic {
    return &RegisterByLogic{
        ctx:    ctx,
        svcCtx: svcCtx,
        Logger: logx.WithContext(ctx),
    }
}

// 定义一个 SayHello 一元 rpc 方法,请求体和响应体必填。
func (l *RegisterByLogic) RegisterByPhone(in *register.RegReq) (*register.RegRes, error) {
    // todo: add your logic here and delete this line
    logx.Info("ucenter 执行了 grpc 注册接口")
    return &register.RegRes{}, nil
}

func (l *RegisterByLogic) SendCode(in *register.CodeReq) (*register.CodeRes, error) {
    code := tools.Rand4Num()
    // 发送验证码(掠过)
    go func() {
        logx.Info("调用短信平台发送验证码成功")
    }()
    logx.Infof("验证码为:%s \n", code)
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    ok, err := l.svcCtx.Redis.SetnxExCtx(ctx, "code", code, 120)
    if err != nil {
        return &register.CodeRes{}, err
    }
    if ok {
        logx.Info("写入验证码成功")
    }

    return &register.CodeRes{}, nil
}

二. 启动微服务时运行流程

  1. 读取配置文件
  2. 根据读取的配置yaml, 先创建服务结构体(redis, mysql, 等待连接)
  3. 根据读取的配置yaml, 注册到etcd服务发现
  4. 根据proto生成的go文件里注册方法, 绑定生成的server服务结构体
  5. 启动

main.go

func main() {
    flag.Parse()

    // 1. 读取配置文件
    var c config.Config
    conf.MustLoad(*configFile, &c)

    // 2. 根据读取的配置, 创建服务上下文结构体
    ctx := svc.NewServiceContext(c)

    // 3. 根据读取的配置, 应该是注册当前的grpc服务到etcd服务发现里面
    s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) {
        // 4. 这里register是生成的grpc的go文件, 再创建当前注册服务结构体对象
        register.RegisterRegisterServer(grpcServer, server.NewRegisterServer(ctx))

        if c.Mode == service.DevMode || c.Mode == service.TestMode {
            reflection.Register(grpcServer)
        }
    })
    defer s.Stop()

    // 5. 启动
    fmt.Printf("Starting rpc server at %s...\n", c.ListenOn)
    s.Start()
}

三. 当请求到来时

1.先到4那里, server<服务结构体>绑定的 RegisterByPhone服务方法 2.方法内调用NewRegisterByLogic()创建<接口结构体>

package server

import (
    "context"

    "ucenter/internal/logic"
    "ucenter/internal/svc"
    "grpc-common/ucenter/types/register"
)

type RegisterServer struct {
    svcCtx *svc.ServiceContext
    register.UnimplementedRegisterServer
}

func NewRegisterServer(svcCtx *svc.ServiceContext) *RegisterServer {
    return &RegisterServer{
        svcCtx: svcCtx,
    }
}

// 定义一个 SayHello 一元 rpc 方法,请求体和响应体必填。
func (s *RegisterServer) RegisterByPhone(ctx context.Context, in *register.RegReq) (*register.RegRes, error) {
    l := logic.NewRegisterByLogic(ctx, s.svcCtx)
    return l.RegisterByPhone(in)
}
func (s *RegisterServer) SendCode(ctx context.Context, in *register.CodeReq) (*register.CodeRes, error) {
    l := logic.NewRegisterByLogic(ctx, s.svcCtx)
    return l.SendCode(in)
}

3.运行<接口结构体>绑定的接口方法RegisterByPhone()

package logic

import (
    "context"
    "mscoin/mscoin-common/tools"
    "time"

    "grpc-common/ucenter/types/register"
    "ucenter/internal/svc"

    "github.com/zeromicro/go-zero/core/logx"
)

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

func NewRegisterByLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RegisterByLogic {
    return &RegisterByLogic{
        ctx:    ctx,
        svcCtx: svcCtx,
        Logger: logx.WithContext(ctx),
    }
}

// 定义一个 SayHello 一元 rpc 方法,请求体和响应体必填。
func (l *RegisterByLogic) RegisterByPhone(in *register.RegReq) (*register.RegRes, error) {
    // todo: add your logic here and delete this line
    logx.Info("ucenter 执行了 grpc 注册接口")
    return &register.RegRes{}, nil
}

func (l *RegisterByLogic) SendCode(in *register.CodeReq) (*register.CodeRes, error) {
    code := tools.Rand4Num()
    // 发送验证码(掠过)
    go func() {
        logx.Info("调用短信平台发送验证码成功")
    }()
    logx.Infof("验证码为:%s \n", code)
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    ok, err := l.svcCtx.Redis.SetnxExCtx(ctx, "code", code, 120)
    if err != nil {
        return &register.CodeRes{}, err
    }
    if ok {
        logx.Info("写入验证码成功")
    }

    return &register.CodeRes{}, nil
}

4.返回