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) 。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章