go-zero
是一个集成了各种工程实践的 web
和 rpc
框架。通过弹性设计保障了大并发服务端的稳定性。go-zero
包含极简的API定义和生成工具goctl
,可以根据自定义的 api
或 proto
文件一键生成 go
代码
环境安装
goctl
goctl
是 go-zero 的内置脚手架,是提升开发效率的一大利器,可以一键生成代码、文档、部署 k8s yaml、dockerfile 等。
# go version < 1.16
go get -u github.com/zeromicro/go-zero/tools/goctl@latest
# go version >= 1.16
go install github.com/zeromicro/go-zero/tools/goctl@latest
protoc
protoc
是一个用于生成代码的工具,它可以根据 proto
文件生成C++、Java、Python、Go、PHP 等多重语言的代码,而 gRPC
的代码生成还依赖 protoc-gen-go
,protoc-gen-go-grpc
插件来配合生成 Go 语言的 gRPC
代码。
goctl env check --install --verbose --force
Etcd
参考《Etcd安装及基本命令》
go-zero 微服务简单应用
比如,我们有一个商城系统,需要在订单模块根据 user_id 查询对应用户信息,那么我们的订单系统就需要开启一个 HTTP
服务,用户系统开启一个 gRPC
服务。
mkdir -p ~/work/mall/order
mkdir -p ~/work/mall/user
cd ~/work/mall
go mod init
用户系统
user/user.proto
# vim user/user.proto
syntax = "proto3";
package user;
// protoc-gen-go 版本大于1.4.0,proto文件需要加上go_package,否则无法生成
option go_package = "./user";
message IdRequest {
int64 id = 1;
}
message UserResponse {
int64 id = 1;
string name = 2;
string gender = 3;
}
service User{
rpc getUser (IdRequest) returns (UserResponse);
}
生成 gRPC
代码
cd order
goctl rpc protoc user.proto --go_out=./types --go-grpc_out=./types --zrpc_out=.
完善用户逻辑代码 user/internal/logic/getuserlogic.go
func (l *GetUserLogic) GetUser(in *user.IdRequest) (*user.UserResponse, error) {
// todo: add your logic here and delete this line
return &user.UserResponse{
Id: in.GetId(),
Name: "Hello Zero",
Gender: "男",
}, nil
}
订单系统
生成api代码
order/order.api
# vim order/order.api
syntax = "v1"
type OrderRequest {
Id int64 `path:"id"`
}
type OrderResponse {
Id int64 `json:"id"`
Status string `json:"status"`
UserId int64 `json:"user_id"`
Username string `json:"username"`
UserGender string `json:"user_gender"`
}
service order-api {
@handler OrderHandler
get /order/:id (OrderRequest) returns (OrderResponse)
}
生成 api
代码
cd user
goctl api go --api order.api --dir .
配置 Etcd
oder/etc/order-api.yaml
# vim oder/etc/order-api.yaml
UserRpc:
Etcd:
Hosts:
- 127.0.0.1:2379
Key: user.rpc
order/internal/config/config.go
# vim order/internal/config/config.go
type Config struct {
rest.RestConf
UserRpc zrpc.RpcClientConf
}
依赖注入
初始化 UserRPC
客户端
order/internal/svc/servicecontext.go
# vim order/internal/svc/servicecontext.go
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)),
}
}
完善订单逻辑代码
func (l *OrderInfoLogic) Order(req *types.OrderRequest) (resp *types.OrderResponse, err error) {
// todo: add your logic here and delete this line
res := &types.OrderResponse{
Id: req.Id,
Status: "UN_PAY",
UserId: 88,
}
// 调用User RPC服务,查询用户信息
userResponse, err := l.svcCtx.UserRpc.GetUser(l.ctx, &user.IdRequest{
Id: res.UserId,
})
if err != nil {
return nil, err
}
res.Username = userResponse.Name
res.UserGender = userResponse.Gender
return res, nil
}
启动
go mod tidy
# 启动 user rpc 服务
cd user
go run user.go
# 启动 order http 服务,默认监听8080端口
cd ../order
go run order.go
浏览器访问 http://127.0.0.1:8888/order/10086
返回了用户信息表示成功
{
"id": 10086,
"status": "UN_PAY",
"user_id": 88,
"username": "Hello Zero",
"user_gender": "男"
}