在上一篇我們已經(jīng)演示了怎樣快速創(chuàng)建一個單體服務(wù),接下來我們來演示一下如何快速創(chuàng)建微服務(wù), 在本小節(jié)中,api部分其實(shí)和單體服務(wù)的創(chuàng)建邏輯是一樣的,只是在單體服務(wù)中沒有服務(wù)間的通訊而已, 且微服務(wù)中api服務(wù)會多一些rpc調(diào)用的配置。
本小節(jié)將以一個訂單服務(wù)調(diào)用用戶服務(wù)來簡單演示一下,演示代碼僅傳遞思路,其中有些環(huán)節(jié)不會一一列舉。
假設(shè)我們在開發(fā)一個商城項(xiàng)目,而開發(fā)者小明負(fù)責(zé)用戶模塊(user)和訂單模塊(order)的開發(fā),我們姑且將這兩個模塊拆分成兩個微服務(wù)
微服務(wù)的拆分也是一門學(xué)問,這里我們就不討論怎么去拆分微服務(wù)的細(xì)節(jié)了。
根據(jù)情景提要我們可以得知,訂單是直接面向用戶,通過http協(xié)議訪問數(shù)據(jù),而訂單內(nèi)部需要獲取用戶的一些基礎(chǔ)數(shù)據(jù),既然我們的服務(wù)是采用微服務(wù)的架構(gòu)設(shè)計(jì), 那么兩個服務(wù)(user, order)就必須要進(jìn)行數(shù)據(jù)交換,服務(wù)間的數(shù)據(jù)交換即服務(wù)間的通訊,到了這里,采用合理的通訊協(xié)議也是一個開發(fā)人員需要 考慮的事情,可以通過http,rpc等方式來進(jìn)行通訊,這里我們選擇rpc來實(shí)現(xiàn)服務(wù)間的通訊,相信這里我已經(jīng)對"rpc服務(wù)存在有什么作用?"已經(jīng)作了一個比較好的場景描述。 當(dāng)然,一個服務(wù)開發(fā)前遠(yuǎn)不止這點(diǎn)設(shè)計(jì)分析,我們這里就不詳細(xì)描述了。從上文得知,我們需要一個
兩個服務(wù)來初步實(shí)現(xiàn)這個小demo。
如果你跑了單體的示例,里面也叫 go-zero-demo,你可能需要換一個父目錄。
$ mkdir go-zero-demo
$ cd go-zero-demo
$ go mod init go-zero-demo
說明:如無 cd 改變目錄的操作,所有操作均在 go-zero-demo 目錄執(zhí)行
$ mkdir -p mall/user/rpc
$ vim mall/user/rpc/user.proto
增加如下代碼:
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);
}
protoc
?,?protoc-gen-go
?,?protoc-gen-grpc-go
? 你可以通過如下指令一鍵安裝:$ goctl env check -i -f
注意: 1、每一個 ?
*.proto
?文件只允許有一個service error: only one service expected
$ cd mall/user/rpc
$ goctl rpc protoc user.proto --go_out=./types --go-grpc_out=./types --zrpc_out=.
Done.
$ vim internal/logic/getuserlogic.go
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
?服務(wù)# 回到 go-zero-demo/mall 目錄
$ mkdir -p order/api && cd order/api
$ vim order.api
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)
}
$ goctl api go -api order.api -dir .
Done.
$ vim 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
}
$ vim etc/order.yaml
Name: order
Host: 0.0.0.0
Port: 8888
UserRpc:
Etcd:
Hosts:
- 127.0.0.1:2379
Key: user.rpc
$ vim internal/svc/servicecontext.go
package svc
import (
"go-zero-demo/mall/order/api/internal/config"
"go-zero-demo/mall/user/rpc/user"
"github.com/zeromicro/go-zero/zrpc"
)
type ServiceContext struct {
Config config.Config
UserRpc user.User
}
func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{
Config: c,
UserRpc: user.NewUser(zrpc.MustNewClient(c.UserRpc)),
}
}
給 getorderlogic 添加業(yè)務(wù)邏輯
$ vim internal/logic/getorderlogic.go
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
# 在 mall/user/rpc 目錄
$ go run user.go -f etc/user.yaml
Starting rpc server at 127.0.0.1:8080...
# 在 mall/order/api 目錄
$ go run order.go -f etc/order.yaml
Starting server at 0.0.0.0:8888...
$ curl -i -X GET http://localhost:8888/api/order/get/1
HTTP/1.1 200 OK
Content-Type: application/json
Date: Sun, 07 Feb 2021 03:45:05 GMT
Content-Length: 30
{"id":"1","name":"test order"}
更多建議: