说明 本次教程主要来自于这里
安装依赖
安装依赖goctl,用命令进行安装:go install github.com/zeromicro/go-zero/tools/goctl@latest
安装成功后,输入go env
找到GOPATH
1 2 3 4 5 E:\proj\gowork\studyGoZero>go env set GO111MODULE=on set GOPATH=C:\Users\Administrator\go set GOROOT=E:\app\Go ....
把C:\Users\Administrator\go\bin\goctl.exe
拷贝到GOROOT\bin目录下
查看版本成功
1 2 E:\proj\gowork> goctl --version goctl version 1.5.4 windows/amd64
1 goctl env check --install --verbose --force
安装protoc
成功后,把C:\Users\Administrator\go\bin\
的相关文件拷贝到GOROOT\bin
go-zero单体服务
创建并初始化项目,生成greet服务为api层(对外接口)
1 2 3 4 5 6 7 E:\proj\gowork>mkdir go-zero-demo E:\proj\gowork>cd go-zero-demo E:\proj\gowork\go-zero-demo>go mod init go-zero-demo go: creating new go.mod: module go-zero-demo E:\proj\gowork\go-zero-demo>goctl api new greet Done. E:\proj\gowork\go-zero-demo>go mod tidy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 E:\proj\gowork\go-zero-demo>tree /f │ go.mod │ go.sum │ └─greet │ greet.api │ greet.go │ ├─etc │ greet-api.yaml │ └─internal ├─config │ config.go │ ├─handler │ greethandler.go │ routes.go │ ├─logic │ greetlogic.go │ ├─svc │ servicecontext.go │ └─types types.go
1 2 3 4 5 6 7 8 9 10 11 12 type Request { Name string `path:"name,options=you|me"` } type Response { Message string `json:"message"` } service greet-api { @handler GreetHandler get /from/:name(Request) returns (Response) // 对外访问接口路径为:/from/name }
编写逻辑 E:\proj\gowork\go-zero-demo\greet\internal\logic\greetlogic.go1
代码中编写如下逻辑:
1 2 3 4 5 func (l *GreetLogic) Greet(req *types.Request) (resp *types.Response, err error) { return &types.Response{ Message: "Hello go-zero", }, nil }
启动并访问服务
1 2 go run .\greet.go Starting server at 0.0.0.0:8888...
浏览器访问:http://localhost:8888/from/you
go-zero 微服务
演示功能目标
订单服务(order)提供一个查询接口
用户服务(user)提供一个方法供订单服务获取用户信息
服务设计分析 根据情景提要我们可以得知,订单是直接面向用户,通过http协议访问数据,而订单内部需要获取用户的一些基础数据,既然我们的服务是采用微服务的架构设计, 那么两个服务(user, order)就必须要进行数据交换,服务间的数据交换即服务间的通讯,到了这里,采用合理的通讯协议也是一个开发人员需要 考虑的事情,可以通过http,rpc等方式来进行通讯,这里我们选择rpc来实现服务间的通讯,相信这里我已经对”rpc服务存在有什么作用?”已经作了一个比较好的场景描述。 当然,一个服务开发前远不止这点设计分析,我们这里就不详细描述了。从上文得知,我们需要一个
两个服务来初步实现这个小demo。
创建工程 1 2 3 E:\proj\gowork>mkdir study-gozero-demo E:\proj\gowork>cd study-gozero-demo E:\proj\gowork\study-gozero-demo>go mod init study-gozero-demo
创建user rpc服务
1 E:\proj\gowork\study-gozero-demo\>mkdir -p mall/user/rpc
注意在win中,我使用的git窗口编写的mkdri命令,在cmd中这样创建有问题
添加user.proto
文件,增加getUser
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 syntax = "proto3"; package user; // protoc-gen-go 版本大于1.4.0, proto文件需要加上go_package,否则无法生成 option go_package = "./user"; message IdRequest { string id = 1; } message UserResponse { // 用户id string id = 1; // 用户名称 string name = 2; // 用户性别 string gender = 3; } service User { rpc getUser(IdRequest) returns(UserResponse); //对外开发的接口 }
1 2 3 4 E:\proj\gowork\study-gozero-demo\mall\user\rpc> goctl rpc protoc user.proto --go_out=. --go-grpc_out=. --zrpc_out=. Done.
vs code ide的终端中执行的此命令.最终生成的go服务源代码文件在目录:E:\proj\gowork\study-gozero-demo\mall\user\rpc\userclient\user.go
填充业务逻辑其实就是user.proto中生成的getUser,目录为:E:\proj\gowork\study-gozero-demo\mall\user\rpc\internal\logic\getuserlogic.go
1 2 3 4 5 6 7 8 9 10 func (l *GetUserLogic) GetUser(in *user.IdRequest) (*user.UserResponse, error) { // todo: add your logic here and delete this line // 新增的代码 return &user.UserResponse{ Id: "1", Name: "test", }, nil }
若发现这里引用包报错,可以使用go mod tidy
下载依赖
创建order api服务
1 2 3 Administrator@WIN-20230710BAT MINGW64 /e/proj/gowork/study-gozero-demo/mall $ mkdir -p order/api && cd order/api
git 窗口执行
编写添加api文件目录为:E:\proj\gowork\study-gozero-demo\mall\order\api\order.api
1 2 3 4 5 6 7 8 9 10 11 12 13 14 type( OrderReq { Id string `path:"id"` } OrderReply { Id string `json:"id"` Name string `json:"name"` } ) service order { @handler getOrder get /api/order/get/:id (OrderReq) returns (OrderReply) }
1 PS E:\proj\gowork\study-gozero-demo\mall\order\api> goctl api go -api order.api -dir .
1 2 3 4 5 6 7 8 9 10 11 12 package config import ( "github.com/zeromicro/go-zero/rest" "github.com/zeromicro/go-zero/zrpc" ) type Config struct { rest.RestConf UserRpc zrpc.RpcClientConf // 这个就是新增的user rpc服务 }
添加yaml配置目录为E\proj\gowork\study-gozero-demo\mall\order\api\etc\order.yaml
1 2 3 4 5 6 7 8 9 Name: order Host: 0.0.0.0 Port: 8888 UserRpc: -- 从这里开始为新增 Etcd: Hosts: - 127.0.0.1:2379 Key: user.rpc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package svc import ( "study-gozero-demo/mall/order/api/internal/config" "study-gozero-demo/mall/user/rpc/userclient" // 引用最终生成user服务代码路径 "github.com/zeromicro/go-zero/zrpc" ) type ServiceContext struct { Config config.Config UserRpc userclient.User // 引用User服务中的GetUser函数 } func NewServiceContext(c config.Config) *ServiceContext { return &ServiceContext{ Config: c, //加入user rpc服务 UserRpc: userclient.NewUser(zrpc.MustNewClient(c.UserRpc)), } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 package logic import ( "context" "errors" "study-gozero-demo/mall/order/api/internal/svc" "study-gozero-demo/mall/order/api/internal/types" // 引用 "study-gozero-demo/mall/user/rpc/user" "github.com/zeromicro/go-zero/core/logx" ) type GetOrderLogic struct { logx.Logger ctx context.Context svcCtx *svc.ServiceContext } func NewGetOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetOrderLogic { return &GetOrderLogic{ Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx, // 引用order的服务,然后才能调用order服务中的user rpc } } func (l *GetOrderLogic) GetOrder(req *types.OrderReq) (resp *types.OrderReply, err error) { // todo: add your logic here and delete this line // 新增代码,注意这里的&user,应用的是user rpc的user/user.pb.go中内容,IdRequest其实就是对应入参(user.proto定义的) // 获取订单之前,需要盘点用户的id是否存在,若不存在则返回用户不存在报错,若存在则返回test order user, err := l.svcCtx.UserRpc.GetUser(l.ctx, &user.IdRequest{ Id: "1", }) if err != nil { return nil, err } if user.Name != "test" { return nil, errors.New("用户不存在") } return &types.OrderReply{ Id: req.Id, Name: "test order", }, nil }
启动服务并验证
注意本地安装etcd ,打开E:\app\etcd-v3.4.27-windows-amd64\etcd.exe
启动服务
etcd是一个分布式一致性键值存储,其主要用于分布式系统的共享配置和服务发现。
1 E:\proj\gowork\study-gozero-demo\mall\user\rpc> go run .\user.go
1 2 3 PS E:\proj\gowork\study-gozero-demo\mall\order\api> go run order.go Starting server at 0.0.0.0:8888... {"@timestamp":"2023-07-26T16:36:58.057+08:00","caller":"stat/usage.go:61","content":"CPU: 0m, MEMORY: Alloc=3.2Mi, TotalAlloc=6.1Mi, Sys=17.9Mi, NumGC=3","level":"stat"}
总结 如上代码展示了,单体服务和微服务分别运用,下一篇文章我们将会加上数据库、jwt鉴权、以及具体的增删改查