这是我参与「第五届青训营 」伴学笔记创作活动的第 7 天
一、本堂课重点内容:
- rpc-user-info讲解
- 个人小结
本文通过项目来进行案例讲解。
二、讲解
本项目rpc框架选用Kitex,并且通过代码生成器进行生成,因此该微服务结构具有Kitex特色,根据Kitex官方文档,开发者只需要关注handler的业务逻辑即可,而负责这块的同学为了代码进一步抽象,将业务逻辑进一步抽象,放到了logic下,下面则会对此进行详细介绍。
- main函数:包括服务注册、服务端生成。
func main() {
// 日志
f, err := os.OpenFile("./user-info.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
panic(err)
}
defer f.Close()
klog.SetOutput(f)
// 服务注册
svr := userInfoPb.NewServer(
new(UserInfoImpl),
server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: "userInfoImpl"}),
server.WithRegistry(registry.NewNacosRegistry(nacos.Cli)),
server.WithServiceAddr(&net.TCPAddr{Port: 50051}),
)
if err := svr.Run(); err != nil {
log.Println("server stopped with error:", err)
} else {
log.Println("server stopped")
}
}
- Handler:这里的代码则是rpc能够调用的代码
func (s *UserInfoImpl) Register(ctx context.Context, req *userInfoPb.RegisterReq) (resp *userInfoPb.RegisterResp, err error) {
// TODO: Your code here...
return logic.Register(req)
}
// Login implements the UserInfoImpl interface.
func (s *UserInfoImpl) Login(ctx context.Context, req *userInfoPb.LoginReq) (resp *userInfoPb.LoginResp, err error) {
// TODO: Your code here...
return logic.Login(req)
}
// Info implements the UserInfoImpl interface.
func (s *UserInfoImpl) Info(ctx context.Context, req *userInfoPb.UserInfoReq) (resp *userInfoPb.UserInfoResp, err error) {
// TODO: Your code here...
return logic.Info(ctx, req)
}
// ActionDB implements the UserInfoImpl interface.
func (s *UserInfoImpl) ActionDB(ctx context.Context, req *userInfoPb.ActionDBReq) (resp *userInfoPb.ActionDBResp, err error) {
// TODO: Your code here...
return logic.ActionDB(ctx, req)
}
// BatchInfo implements the UserInfoImpl interface.
func (s *UserInfoImpl) BatchInfo(ctx context.Context, req *userInfoPb.BatchUserReq) (resp *userInfoPb.BtachUserResp, err error) {
// TODO: Your code here...
return logic.BatchInfo(ctx, req)
- logic:具体的业务逻辑实现,以登录为例。其他的根据接口的不同,选择不同的储存策略,例如修改信息为了保证数据库和缓存一致性,采用双删策略。为了缓解io瓶颈,对于用户信息采用缓存策略。
func Login(req *userInfoPb.LoginReq) (resp *userInfoPb.LoginResp, err error) {
resp = new(userInfoPb.LoginResp)
user := models.UserInfo{}
userReq := models.UserInfo{UserName: req.UserName, Password: req.Password}
err = models.DB.Where("user_name = ?", userReq.UserName).First(&user).Error
if err != nil {
resp.StatusCode = 1
resp.StatusMsg = "查询失败"
return resp, err
}
isValid := utils.ValidPassword(userReq.Password, user.Salt, user.Password)
if !isValid {
resp.StatusCode = 1
resp.StatusMsg = "密码错误"
return resp, err
}
token, err := utils.GenerateToken(user.ID, user.UserName)
if err != nil {
resp.StatusCode = 1
resp.StatusMsg = "生成token失败"
return resp, err
}
resp.StatusCode = 0
resp.StatusMsg = "查询成功"
resp.UserId = uint64(int64(user.ID))
resp.Token = token
return resp, nil
}