快速开始
单体服务
创建greet服务
| $ mkdir go-zero-demo
$ cd go-zero-demo
$ go mod init go-zero-demo
$ goctl api new greet
$ go mod tidy
Done.
|
查看一下greet服务的目录结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 | $ tree greet
greet
├── etc
│ └── greet-api.yaml
├── greet.api
├── greet.go
└── internal
├── config
│ └── config.go
├── handler
│ ├── greethandler.go
│ └── routes.go
├── logic
│ └── greetlogic.go
├── svc
│ └── servicecontext.go
└── types
└── types.go
|
由以上目录结构可以观察到,greet服务虽小,但"五脏俱全"。接下来我们就可以在greetlogic.go中编写业务代码了。
编写逻辑
| func (l *GreetLogic) Greet(req *types.Request) (resp *types.Response, err error) {
return &types.Response{
Message: "Hello go-zero",
}, nil
}
|
启动并访问服务
启动服务
| $ cd greet
$ go run greet.go -f etc/greet-api.yaml
|
输出如下,服务启动并侦听在8888端口:
| Starting server at 0.0.0.0:8888...
|
访问服务
| $ curl -i -X GET http://localhost:8888/from/you
|
返回如下:
| HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Traceparent: 00-2b3fad2495fe9ed5fcd912b64816d0ec-573ad10c4d1ca664-00
Date: Mon, 31 Oct 2022 05:35:05 GMT
Content-Length: 27
{"message":"Hello go-zero"}
|
微服务
假设我们在开发一个商城项目,而开发者小明负责用户模块(user)和订单模块(order)的开发,我们姑且将这两个模块拆分成两个微服务
- 订单服务(order)提供一个查询接口
- 用户服务(user)提供一个方法供订单服务获取用户信息
根据情景提要我们可以得知,订单是直接面向用户,通过http协议访问数据,而订单内部需要获取用户的一些基础数据,既然我们的服务是采用微服务的架构设计,
那么两个服务(user, order)就必须要进行数据交换,服务间的数据交换即服务间的通讯,到了这里,采用合理的通讯协议也是一个开发人员需要 考虑的事情,
可以通过http,rpc等方式来进行通讯,这里我们选择rpc来实现服务间的通讯,相信这里我已经对"rpc服务存在有什么作用?"已经作了一个比较好的场景描述。
当然,一个服务开发前远不止这点设计分析,我们这里就不详细描述了。从上文得知,我们需要一个
两个服务来初步实现这个小demo。
创建mall工程
| ➜ mkdir go-zero-mall
➜ cd go-zero-mall
➜ go mod init go-zero-mall
go: creating new go.mod: module go-zero-mall
|
创建user rpc服务
创建user rpc服务
添加user.proto文件,增加getUser方法
mall/user/rpc/user.proto
:
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);
}
|
生成代码
| $ cd mall/user/rpc
$ goctl rpc protoc user.proto --go_out=./types --go-grpc_out=./types --zrpc_out=.
Done.
|
填充业务逻辑
internal/logic/getuserlogic.go
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 | package logic
import (
"context"
"go-zero-demo/mall/user/rpc/internal/svc"
"go-zero-demo/mall/user/rpc/types/user"
"github.com/zeromicro/go-zero/core/logx"
)
type GetUserLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewGetUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserLogic {
return &GetUserLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *GetUserLogic) GetUser(in *user.IdRequest) (*user.UserResponse, error) {
return &user.UserResponse{
Id: "1",
Name: "test",
}, nil
}
|
创建order api服务
| # 回到 go-zero-demo/mall 目录
$ mkdir -p order/api && cd order/api
|
添加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)
}
|
生成order服务
| $ goctl api go -api order.api -dir .
Done.
|
添加user rpc配置
internal/config/config.go
:
| package config
import (
"github.com/zeromicro/go-zero/zrpc"
"github.com/zeromicro/go-zero/rest"
)
type Config struct {
rest.RestConf
UserRpc zrpc.RpcClientConf
}
|
添加yaml配置
etc/order.yaml
| Name: order
Host: 0.0.0.0
Port: 8888
UserRpc:
Etcd:
Hosts:
- 127.0.0.1:2379
Key: user.rpc
|
完善服务依赖
internal/svc/servicecontext.go
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 | package svc
import (
"go-zero-demo/mall/order/api/internal/config"
"go-zero-demo/mall/user/rpc/userclient"
"github.com/zeromicro/go-zero/zrpc"
)
type ServiceContext struct {
Config config.Config
UserRpc userclient.User
}
func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{
Config: c,
UserRpc: userclient.NewUser(zrpc.MustNewClient(c.UserRpc)),
}
}
|
添加order演示逻辑
给 getorderlogic 添加业务逻辑
internal/logic/getorderlogic.go
:
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 | package logic
import (
"context"
"errors"
"go-zero-demo/mall/order/api/internal/svc"
"go-zero-demo/mall/order/api/internal/types"
"go-zero-demo/mall/user/rpc/types/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,
}
}
func (l *GetOrderLogic) GetOrder(req *types.OrderReq) (*types.OrderReply, error) {
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
下载依赖
| # 在 go-zero-demo 目录下
$ go mod tidy
|
启动user rpc
| # 在 mall/user/rpc 目录
$ go run user.go -f etc/user.yaml
Starting rpc server at 127.0.0.1:8080...
|
启动order api
| # 在 mall/order/api 目录
$ go run order.go -f etc/order.yaml
Starting server at 0.0.0.0:8888...
|
访问order api
| ➜ ~ curl -i -X GET http://localhost:8888/api/order/get/1
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Traceparent: 00-6754c66dfc5d4dba63c3bc6902ce1bb3-686f34deaeac4fdb-00
Date: Mon, 31 Oct 2022 15:26:22 GMT
Content-Length: 30
{"id":"1","name":"test order"}
|
etcd log:
| {"level":"info","ts":"2022-10-31T23:23:09.575+0800","caller":"embed/serve.go:146","msg":"serving client traffic insecurely; this is strongly discouraged!","address":"127.0.0.1:2379"}
|