烦不烦 發表於 2022-7-1 15:00:00

go-zero实战demo(一)

<h3 id="前言">前言</h3>
<p>听说下一个项目 可能要用微服务开发,趁着项目的空档期,对于go微服务的框架进行了学习。目前go的微服务框架个人认为处于百家齐放的时代,可能这也是go的生态的一个特点吧,也曾简单用过go-miecro,gin+micro+gorm+mysql+redis 常见方案使用起来还是蛮顺手的,可惜该框架成了个人仓库,生成的依赖会出现引用错误,其他的都蛮ok的。对于go-zero的选择,其实参考此篇文章:https://zhuanlan.zhihu.com/p/488233067 , 再加团队沟通协商及个人私心(认为其可以成为趋势及给自己加分)。 所以选择的go 微服务框架为go-zero。</p>
<h3 id="版本浅介">版本浅介</h3>
<blockquote>
<p>go:1.17.6</p>
<p>protoc:3.20.1</p>
<p>goctl:1.3.8</p>
<p>mysql:8.0.29</p>
<p>redis:7.0.0</p>
<p>consul:1.12</p>
</blockquote>
<h3 id="demo-介绍">demo 介绍</h3>
<blockquote>
<p>实现简单的用户表 增查</p>
<p>使用consul 替换etcd</p>
</blockquote>
<h4 id="相关接口">相关接口</h4>
<pre><code class="language-shell">/api/user/login                            登录
�/api/user/register                        注册
�/api/user/listuser                     查询所有用户
�/api/user/userinfo                        查询 某个用户详情
</code></pre>
<p>源码:https://github.com/zisefeizhu/go-zero-demo</p>
<p>参考:</p>
<blockquote>
<p>go-zero作者</p>
<p>https://www.cnblogs.com/kevinwan/category/2002486.html</p>
<p>go-zero 入门级demo</p>
<p>https://juejin.cn/post/7036011410265997348</p>
</blockquote>
<h3 id="demo-注意点">demo 注意点</h3>
<p>常用命令</p>
<pre><code class="language-shell">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
</code></pre>
<h4 id="1consul-替换etcd">1、consul 替换etcd</h4>
<blockquote>
<p>参考文章:https://github.com/zeromicro/zero-contrib/tree/main/zrpc/registry/consul</p>
</blockquote>
<h5 id="微服务">微服务</h5>
<p>rpc/etcd/user.yaml</p>
<pre><code class="language-shell"># consul   替换etcd
Consul:
Host: 127.0.0.1:8500 # consul endpoint
Key: user.rpc # 注册到consul的服务名字
Meta:
    Protocol: grpc
Tag:
    - tag
    - rpc
</code></pre>
<p>rpc/internal/config/config.go</p>
<pre><code class="language-shell">type Config struct {
        zrpc.RpcServerConf
        Mysql struct {
                DataSource string
        }
        // consul
        Consul   consul.Conf
        CacheRedis cache.CacheConf
        Salt       string
}
</code></pre>
<p>rpc/user.go</p>
<pre><code class="language-shell">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()
</code></pre>
<h5 id="api">api</h5>
<p>api/etcd/user.yaml</p>
<pre><code class="language-shell">UserRpc:
Target: consul://127.0.0.1:8500/user.rpc?wait=14s
NonBlock: true
</code></pre>
<p>api/internalconfig/config.go</p>
<pre><code class="language-shell">type Config struct {
        rest.RestConf
        Auth struct {
                AccessSecret string
                AccessExpire int64
        }
        UserRpc zrpc.RpcClientConf
}
</code></pre>
<p>api/user.go</p>
<pre><code class="language-shell">import (
        _ "github.com/zeromicro/zero-contrib/zrpc/registry/consul"
)
</code></pre>
<h5 id="2api层的userapi-书写">2、api层的user.api 书写</h5>
<blockquote>
<p>参考文档:https://go-zero.dev/cn/docs/design/grammar/#type语法块</p>
</blockquote>
<p>例:</p>
<pre><code class="language-shell">type (
        // 用户登录
        LoginRequest {
                Mobile   string `json:"mobile"`
                Password string `json:"password"`
        }
        LoginResponse {
                AccessTokenstring `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)
}
</code></pre>
<h5 id="3model层">3、model层</h5>
<p>go-zero不会根据sql自动创建表结构,但是可以根据表结构创建dao层</p>
<blockquote>
<p>参考:https://go-zero.dev/cn/docs/advance/model-gen</p>
</blockquote>
<p>通常只会生成:Insert / FindOne / FindOneByxxx/Update/Delete 方法,其他方法需要自己填充</p>
<p>例:<br>
rpc/model/usermpdel_gen.go</p>
<p>添加FindList方法</p>
<pre><code class="language-shell">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(&amp;resp, query)
        switch err {
        case nil:
                return resp, nil
        case sqlc.ErrNotFound:
                return nil, ErrNotFound
        default:
                return nil, err
        }
}
</code></pre>
<blockquote>
<p>参考:https://talkgo.org/t/topic/1461</p>
</blockquote>
<h5 id="4rpc-业务逻辑实现">4、rpc 业务逻辑实现</h5>
<p>rpc 层重点关注rpc/internal/logic 目录,内是业务的真正实现</p>
<p>以查所有用户为例</p>
<pre><code class="language-shell">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, &amp;user.UserInfoResponse{
                        Id:   item.Id,
                        Name:   item.Name,
                        Gender: item.Gender,
                        Mobile: item.Mobile,
                })
        }
        return &amp;user.ListUserResponse{
                Data: resp,
        }, nil
}
</code></pre>
<h5 id="5go-zero的proto-书写">5、go-zero的proto 书写</h5>
<p>在proto中如果func 没有参数,不能:grpc-go protobuf Empty ,而是定位为空message</p>
<blockquote>
<p>参考:https://github.com/zeromicro/go-zero/issues/825</p>
</blockquote>
<h5 id="6对于go-zero的还需改造点">6、对于go-zero的还需改造点</h5>
<blockquote>
<p>1、配置文件读取环境变量</p>
<p>2、设置context的超时时间</p>
<p>3、将go-zero里的rpc和api分别build成可执行程序</p>
<p>4、等</p>
</blockquote>
<h3 id="总结">总结</h3>
<p>总的来说go-zero使用起来有一些束缚 ,不如micro 灵活随意。不可否认的是go-zero封装的相对更好,使开发者基本只用关注业务逻辑。<br>
在业务全面容器化及以istio为主的服务治理越来越主流的当下及未来:个人觉得在代码层面实现服务治理能力似乎不能算是一种优势。其实在以kubernetes 为标准的容器深度发展的当下,客人认为开发者应该回到重点关注业务的实现逻辑,而治理应下移到基础设施层,即Kubernetes + 业务 + 服务治理(istio) 。</p>


</div>
<div id="MySignature" role="contentinfo">
    过手如登山,一步一重天<br><br>
来源:https://www.cnblogs.com/zisefeizhu/p/16434695.html
頁: [1]
查看完整版本: go-zero实战demo(一)