这是我参与「第五届青训营 」伴学笔记创作活动的第 3 天
背景
easynote service 可以分为三个服务,具体如下;
| Service Name | Usage | Framework | protocol | Path | IDL |
|---|---|---|---|---|---|
| demoapi | http interface | kitex/hertz | http | bizdemo/easy_note/cmd/api | |
| demouser | user data management | kitex/gorm | protobuf | bizdemo/easy_note/cmd/user | bizdemo/easy_note/idl/user.proto |
| demonote | note data management | kitex/gorm | thrift | bizdemo/easy_note/cmd/note | bizdemo/easy_note/idl/note.thrift |
调用关系图
http
┌────────────────────────┐
┌─────────────────────────┤ ├───────────────────────────────┐
│ │ demoapi │ │
│ ┌──────────────────► │◄──────────────────────┐ │
│ │ └───────────▲────────────┘ │ │
│ │ │ │ │
│ │ │ │ │
│ │ │ │ │
│ │ resolve │ │
│ │ │ │ │
req resp │ resp req
│ │ │ │ │
│ │ │ │ │
│ │ │ │ │
│ │ ┌──────────▼─────────┐ │ │
│ │ │ │ │ │
│ │ ┌───────────► Etcd ◄─────────────────┐ │ │
│ │ │ │ │ │ │ │
│ │ │ └────────────────────┘ │ │ │
│ │ │ │ │ │
│ │ register register │ │
│ │ │ │ │ │
│ │ │ │ │ │
│ │ │ │ │ │
│ │ │ │ │ │
┌▼──────┴───────┴───┐ ┌──┴────────┴───────▼─┐
│ │───────────────── req ────────────────────►│ │
│ demonote │ │ demouser │
│ │◄──────────────── resp ────────────────────│ │
└───────────────────┘ └─────────────────────┘
thrift protobuf
分析:
-
user、note两个微服务分别处理用户和笔记两个业务,向下连接数据库,向上为api微服务提供接口。
其业务层和数据库之间的操作由ORM框架 gorm 来提供支持。
提供的接口通过 RPC框架kitex 来创建通信的基础设施(server,client),RPC通信的协议则是 thrift 和 protobuf
-
api服务处理前端请求转发
具体使用 Restful HTTP协议,处理转发的逻辑由 http框架 hertz 来支持
-
api服务调用user、note微服务的抽象功能
这里微服务层次为 Faas(Function as a Service),user、note暴露出API接口,api服务只需要进行调用即可
重点结构
ORM框架
链接 业务 和 数据
比如下面的创建、查询逻辑,在cmd/user/dal/db/user.go中
import (
"context"
"gorm.io/gorm"
)
type User struct {
gorm.Model
UserName string `json:"user_name"`
Password string `json:"password"`
}
func (u *User) TableName() string {
return constants.UserTableName
}
// CreateUser create user info
func CreateUser(ctx context.Context, users []*User) error {
return DB.WithContext(ctx).Create(users).Error
}
// QueryUser query list of user info
func QueryUser(ctx context.Context, userName string) ([]*User, error) {
res := make([]*User, 0)
if err := DB.WithContext(ctx).Where("user_name = ?", userName).Find(&res).Error; err != nil {
return nil, err
}
return res, nil
}
首先创建 schema,定义表名方法
在初始化时,定义了DB变量( var DB *gorm.DB)
然后调用DB的方法来操作数据库,背后逻辑仍然为SQL
HTTP框架
import "github.com/cloudwego/hertz/pkg/app/server"
r := server.New(
server.WithHostPorts("127.0.0.1:8080"),
server.WithHandleMethodNotAllowed(true),
)
v1 := r.Group("/v1")
user1 := v1.Group("/user")
user1.POST("/login", authMiddleware.LoginHandler)
user1.POST("/register", handlers.Register)
这里 r 为 reciver 的缩写,意思是接收前端request的处理器
上面代码就掩饰了路径分发的逻辑
Kitex框架
源码的复杂点,涉及IDL,自动生成,服务,RPC等逻辑
在下一次笔记中给出总结