• gozero实战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) 。

  • 相关阅读:
    Python 存储引擎 数据类型 主键
    Python 数据库
    Python 线程池进程池 异步回调 协程 IO模型
    Python GIL锁 死锁 递归锁 event事件 信号量
    Python 进程间通信 线程
    Python 计算机发展史 多道技术 进程 守护进程 孤儿和僵尸进程 互斥锁
    Python 异常及处理 文件上传事例 UDP socketserver模块
    Python socket 粘包问题 报头
    Django基础,Day7
    Django基础,Day6
  • 原文地址:https://www.cnblogs.com/zisefeizhu/p/16434695.html
Copyright © 2020-2023  润新知