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(&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, &user.UserInfoResponse{
Id: item.Id,
Name: item.Name,
Gender: item.Gender,
Mobile: item.Mobile,
})
}
return &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]