go-zero实战demo(一)

前言

听说下一个项目 可能要用微服务开发,趁着项目的空档期,对于go微服务的框架进行了学习。目前go的微服务框架个人认为处于百家齐放的时代,可能这也是go的生态的一个特点吧,也曾简单用过go-miecro,gin+micro+gorm+mysql+redis 常见方案使用起来还是蛮顺手的,可惜该框架成了个人仓库,生成的依赖会出现引用错误,其他的都蛮ok的。对于go-zero的选择,其实参考此篇文章:https://zhuanlan.zhihu.com/p/488233067 , 再加团队沟通协商及个人私心(认为其可以成为趋势及给自己加分)。 所以选择的go 微服务框架为go-zero。

版本浅介

go:1.17.6

protoc:3.20.1

goctl:1.3.8

mysql:8.0.29

redis:7.0.0

consul:1.12

demo 介绍

实现简单的用户表 增查

使用consul 替换etcd

相关接口

/api/user/login    			登录
�/api/user/register			注册
�/api/user/listuser		       查询所有用户
�/api/user/userinfo			查询 某个用户详情

源码:https://github.com/zisefeizhu/go-zero-demo

参考:

go-zero作者

https://www.cnblogs.com/kevinwan/category/2002486.html

go-zero 入门级demo

https://juejin.cn/post/7036011410265997348

demo 注意点

常用命令

touch user.api
goctl api go -api ./user.api -dir .
goctl model mysql ddl -src user.sql -dir . -c
touch user.proto
goctl rpc protoc ./rpc/user.proto --go_out=./rpc/types --go-grpc_out=./rpc/types  --zrpc_out=./rpc

1、consul 替换etcd

参考文章:https://github.com/zeromicro/zero-contrib/tree/main/zrpc/registry/consul

微服务

rpc/etcd/user.yaml

# consul   替换etcd
Consul:
  Host: 127.0.0.1:8500 # consul endpoint
  Key: user.rpc # 注册到consul的服务名字
  Meta:
    Protocol: grpc
  Tag:
    - tag
    - rpc

rpc/internal/config/config.go

type Config struct {
	zrpc.RpcServerConf
	Mysql struct {
		DataSource string
	}
	// consul
	Consul     consul.Conf
	CacheRedis cache.CacheConf
	Salt       string
}

rpc/user.go

import (
	"github.com/zeromicro/zero-contrib/zrpc/registry/consul"
  
  
func main(){
...... 
err := consul.RegisterService(c.ListenOn, c.Consul)
	if err != nil {
		os.Exit(1)
	}
 
defer s.Stop()
api

api/etcd/user.yaml

UserRpc:
 Target: consul://127.0.0.1:8500/user.rpc?wait=14s
 NonBlock: true

api/internalconfig/config.go

type Config struct {
	rest.RestConf
	Auth struct {
		AccessSecret string
		AccessExpire int64
	}
	UserRpc zrpc.RpcClientConf
}

api/user.go

import (
  	_ "github.com/zeromicro/zero-contrib/zrpc/registry/consul"
)
2、api层的user.api 书写

参考文档:https://go-zero.dev/cn/docs/design/grammar/#type语法块

例:

type (
	// 用户登录
	LoginRequest {
		Mobile   string `json:"mobile"`
		Password string `json:"password"`
	}
	LoginResponse {
		AccessToken  string `json:"accessToken"`
		AccessExpire int64  `json:"accessExpire"`
	}
	// 用户登录

	// 用户注册
	RegisterRequest {
		Name     string `json:"name"`
		Gender   int64  `json:"gender"`
		Mobile   string `json:"mobile"`
		Password string `json:"password"`
	}
	RegisterResponse {
		Id     int64  `json:"id"`
		Name   string `json:"name"`
		Gender int64  `json:"gender"`
		Mobile string `json:"mobile"`
	}
	// 用户注册

	// 用户信息
	UserInfoResponse {
		Id     int64  `json:"id"`
		Name   string `json:"name"`
		Gender int64  `json:"gender"`
		Mobile string `json:"mobile"`
	}

	// 列出所有用户
	ListUserResponse {
		Id     int64  `json:"id"`
		Name   string `json:"name"`
		Gender int64  `json:"gender"`
		Mobile string `json:"mobile"`
	}

	// 用户信息
)

service User {
	@handler Login
	post /api/user/login(LoginRequest) returns (LoginResponse)
	
	@handler Register
	post /api/user/register(RegisterRequest) returns (RegisterResponse)
	
	@handler ListUser
	post /api/user/listuser returns (ListUserResponse)
}

@server(
	jwt: Auth
)
service User {
	@handler UserInfo
	post /api/user/userinfo returns (UserInfoResponse)
}
3、model层

go-zero不会根据sql自动创建表结构,但是可以根据表结构创建dao层

参考:https://go-zero.dev/cn/docs/advance/model-gen

通常只会生成:Insert / FindOne / FindOneByxxx/Update/Delete 方法,其他方法需要自己填充

例:
rpc/model/usermpdel_gen.go

添加FindList方法

userModel interface {
		Insert(ctx context.Context, data *User) (sql.Result, error)
		FindOne(ctx context.Context, id int64) (*User, error)
		FindOneByMobile(ctx context.Context, mobile string) (*User, error)
		FindList() ([]*User, error)  // 新增
		Update(ctx context.Context, newData *User) error
		Delete(ctx context.Context, id int64) error
	}
  
  // 实现
 func (m *defaultUserModel) FindList() ([]*User, error) {
	var resp []*User
	query := fmt.Sprintf("select %s from %s ", userRows, m.table)
	err := m.QueryRowsNoCache(&resp, query)
	switch err {
	case nil:
		return resp, nil
	case sqlc.ErrNotFound:
		return nil, ErrNotFound
	default:
		return nil, err
	}
}

参考:https://talkgo.org/t/topic/1461

4、rpc 业务逻辑实现

rpc 层重点关注rpc/internal/logic 目录,内是业务的真正实现

以查所有用户为例

func (l *ListUserLogic) ListUser(in *user.ListUserRequest) (*user.ListUserResponse, error) {
	results, err := l.svcCtx.UserModel.FindList()
	if err != nil {
		if err == model.ErrNotFound {
			return nil, status.Error(100, "用户不存在")
		}
		return nil, status.Error(500, err.Error())
	}
	resp := make([]*user.UserInfoResponse, 0, len(results))

	for _, item := range results {
		resp = append(resp, &user.UserInfoResponse{
			Id:     item.Id,
			Name:   item.Name,
			Gender: item.Gender,
			Mobile: item.Mobile,
		})
	}
	return &user.ListUserResponse{
		Data: resp,
	}, nil
}
5、go-zero的proto 书写

在proto中如果func 没有参数,不能:grpc-go protobuf Empty ,而是定位为空message

参考:https://github.com/zeromicro/go-zero/issues/825

6、对于go-zero的还需改造点

1、配置文件读取环境变量

2、设置context的超时时间

3、将go-zero里的rpc和api分别build成可执行程序

4、等

总结

总的来说go-zero使用起来有一些束缚 ,不如micro 灵活随意。不可否认的是go-zero封装的相对更好,使开发者基本只用关注业务逻辑。
在业务全面容器化及以istio为主的服务治理越来越主流的当下及未来:个人觉得在代码层面实现服务治理能力似乎不能算是一种优势。其实在以kubernetes 为标准的容器深度发展的当下,客人认为开发者应该回到重点关注业务的实现逻辑,而治理应下移到基础设施层,即Kubernetes + 业务 + 服务治理(istio) 。

posted @ 2022-07-01 15:00  紫色飞猪  阅读(4283)  评论(0编辑  收藏  举报