【Go语言实战】 (14) Gin+gRPC 微服务实现备忘录 (上) | 用户模块

写在前面

介于很多同学让我出一下关于gRPC的内容,我就用gRPC把备忘录重新做一遍。

源码地址:

https://github.com/CocaineCong/gRPC-todoList

1. 安装部分

1.1 安装gRPC

go get google.golang.org/grpc
go get google.golang.org/protobuf

1.2 安装protoc

可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。

下载proto,我是下载这个的。
在这里插入图片描述

然后解压出来把bin目录放在直接放在系统变量当中

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
验证
在这里插入图片描述

2. 用户模块

2.1 总体项目架构

user/
├── cmd                   // 启动入口
├── config                // 配置文件
├── discovery             // etcd服务注册、keep-alive、获取服务信息等等
├── internal              // 业务逻辑(不对外暴露)
│   ├── handler           // 视图层
│   ├── cache             // 缓存模块
│   ├── repository        // 持久层
│   └── service           // 服务层
│       └──pb             // 放置生成的pb文件
├── logs                  // 放置打印日志模块
├── pkg                   // 各种包
│   ├── e                 // 统一错误状态码
│   ├── res               // 统一response接口返回
│   └── util              // 各种工具、JWT、Logger等等..
├── routes                // http路由模块
└── wrappers              // 各个服务之间的熔断降级

2.2 proto文件定义

  • user/internal/service/pb
syntax="proto3";
package pb;
option go_package = "/internal/service;service";

message UserModel {
    // @inject_tag: json:"user_id"
    uint32 UserID=1;
    // @inject_tag: json:"user_name"
    string UserName=2;
    // @inject_tag: json:"nick_name"
    string NickName=3;
}

执行

protoc -I internal/service/pb internal/service/pb/*.proto --go_out=plugins=grpc:.

生成 pb.go 文件

  • user/service/pb

定义user模块的请求和返回的结构类型,已经rpc方法。

syntax="proto3";
package pb;
import "userModels.proto";
option go_package = "/internal/service;service";

message UserRequest{
  // @inject_tag: json:"nick_name" form:"nick_name" uri:"nick_name"
  string NickName=1;
  // @inject_tag: json:"user_name" form:"user_name" uri:"user_name"
  string UserName=2;
  // @inject_tag: json:"password" form:"password" uri:"password"
  string Password=3;
  // @inject_tag: json:"password_confirm" form:"password_confirm" uri:"password_confirm"
  string PasswordConfirm=4;
}

message UserDetailResponse{
  UserModel UserDetail=1;
  uint32 Code=2;
}

service UserService{
  rpc UserLogin(UserRequest) returns(UserDetailResponse);
  rpc UserRegister(UserRequest) returns(UserDetailResponse);
  rpc UserLogout(UserRequest) returns(UserDetailResponse);
}

2.3 repository

这一层主要是对持久化的操作,基础的业务操作。

type User struct {
	UserID         uint      `gorm:"primarykey"`
	UserName       string    `gorm:"unique"`
	NickName       string
	PasswordDigest string
}
  • 视图返回
func BuildUser(item User) *service.UserModel {
	userModel := service.UserModel{
		UserID:   uint32(item.UserID),
		NickName: item.NickName,
		UserName: item.UserName,
	}
	return &userModel
}

2.4 接入ETCD服务发现

  • user/cmd/main.go

新建一个etcd节点

etcdAddress := []string{viper.GetString("etcd.address")}
// 服务注册
etcdRegister := discovery.NewRegister(etcdAddress, logrus.New())
grpcAddress := viper.GetString("server.grpcAddress")

接入user节点

userNode := discovery.Server{
		Name: viper.GetString("server.domain"),
		Addr: grpcAddress,
	}

节点绑定服务

service.RegisterUserServiceServer(server, handler.NewUserService())

服务注册

if _, err := etcdRegister.Register(userNode, 10); err != nil {
	panic(fmt.Sprintf("start server failed, err: %v", err))
}

3. 接入网关

3.1 router

  • api-gateway/routes/router.go

引入gin作为http网关

func NewRouter(service ...interface{}) *gin.Engine {
	ginRouter := gin.Default()
	ginRouter.Use(middleware.Cors(), middleware.InitMiddleware(service), middleware.ErrorMiddleware())
	store := cookie.NewStore([]byte("something-very-secret"))
	ginRouter.Use(sessions.Sessions("mysession", store))
	v1 := ginRouter.Group("/api/v1")
	{
		v1.GET("ping", func(context *gin.Context) {
			context.JSON(200, "success")
		})
		// 用户服务
		v1.POST("/user/register", handler.UserRegister)
		v1.POST("/user/login", handler.UserLogin)
	}
	return ginRouter
}

3.2 网关连接etcd

与user进行连接,获取user服务

userConn, _ := grpc.Dial("127.0.0.1:10001", opts...)
userService := service.NewUserServiceClient(userConn)

3.3 调用服务

  • api-gateway/internal/handler/user.go
func UserRegister(ginCtx *gin.Context) {
	var userReq service.UserRequest
	PanicIfUserError(ginCtx.Bind(&userReq))
	// 从gin.Key中取出服务实例
	userService := ginCtx.Keys["user"].(service.UserServiceClient)
	userResp, err := userService.UserRegister(context.Background(), &userReq)
	PanicIfUserError(err)
	r := res.Response{
		Data:   userResp,
		Status: uint(userResp.Code),
		Msg:    e.GetMsg(uint(userResp.Code)),
	}
	ginCtx.JSON(http.StatusOK, r)
}
  • 7
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
Go微服务开发是利用Go语言进行微服务架构的开发方式。在这个问题中,使用了gingrpc和etcd进行重构grpc-todolist项目。 Gin是一个轻量级的Web框架,使用它可以快速构建高性能的Web应用程序。它具有简单易用、性能出色和灵活的特点。在微服务开发中,Gin可以作为HTTP服务器框架,处理和响应客户端的HTTP请求。 gRPC是一种高性能、开源的远程过程调用(RPC)框架。它支持多种编程语言,并使用带有协议缓冲区的Google Protocol Buffers进行数据交换。在微服务架构中,gRPC可以用于服务之间的通信,通过定义接口和消息格式,实现服务间的数据传输和调用。 Etcd是一个高可靠、分布式的键值存储系统。它使用Raft一致性算法来保证数据的可靠性和一致性。在微服务开发中,Etcd可以作为服务发现和配置管理的工具,用于注册和发现各个微服务的信息。 对于重构grpc-todolist项目来说,使用gin可以将原有的HTTP接口改写为更加高性能的接口,提高整个系统的性能。通过使用gRPC,可以将原有的接口定义为gRPC接口,实现服务间的高效通信,并且易于扩展和维护。同时,借助Etcd实现服务注册和发现,提高系统的可用性和灵活性。 总而言之,通过使用gingrpc和etcd对grpc-todolist项目进行重构,可以提高系统性能、扩展性和可维护性。这种微服务开发方式能够更好地适应大规模分布式系统的需求,使得系统更加稳定和可靠。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小生凡一

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值