基于GRPC结合Consul实现微服务调用
1 )环境准备
- 基于 go workspace 准备3个包: protos,server, client
- 新建 demo目录,其内部结构如下
├── protos │ ├── go.mod │ └── users │ ├── users.proto │ ├── users.pb.go │ └── users_grpc.pb.go ├── server │ ├── go.mod │ └── main.go ├── client │ ├── go.mod │ └── main.go └── go.work
- 这里可以看出是对用户操作的业务场景
- 其实目前无关业务场景,用一个简单的示例来演示grpc和consul的结合
- 这里可以看到,已经初始化了每个包,同时也基于 go work 处理了3个包之前可以调用的关系
- 这里不再过多阐述,参考之前的博文
- https://blog.csdn.net/Tyro_java/article/details/135430134
- https://blog.csdn.net/Tyro_java/article/details/135297367
- 启动 consul, $
consul agent -dev
- 参考:https://blog.csdn.net/Tyro_java/article/details/129992606
2 )准备 protos
- 由上面的目录设计可知,需要 users.proto
syntax="proto3"; option go_package="./users";service Users {rpc AddUser(AddUserReq) returns (AddUserRes);rpc GetUser(GetUserReq) returns (GetUserRes); }message UsersModel {string name = 1;int32 age = 2; }message AddUserReq {UsersModel user = 1; }message AddUserRes {string message = 1;bool success = 2; }message GetUserReq { }message GetUserRes {repeated UsersModel userList =1 ; }
- 进入 demo/protos/users 目录生成 users.pb.go,users_grpc.pb.go
- 执行
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative ./users.proto
- 执行
3 )处理 server
-
新建 demo/server/main.go
package mainimport ("context""fmt""protos/users""net""strconv""google.golang.org/grpc""github.com/hashicorp/consul/api" )// 定义通用度变量 var (host string = "127.0.0.1"port int = 9000portStr string = strconv.Itoa(port)address = host + ":" + portStr )type Users struct {users.UnimplementedUsersServer }func (g Users) AddUser(c context.Context, req *users.AddUserReq) (*users.AddUserRes, error) {fmt.Println(req)return &users.AddUserRes{Success: true,Message: "增加用户成功",}, nil }func (g Users) GetUser(c context.Context, req *users.GetUserReq) (*users.GetUserRes, error) {var tempList []*users.UsersModelfor i := 0; i < 10; i++ {tempList = append(tempList, &users.UsersModel{Name: "商品" + strconv.Itoa(i),Age: int32(i),})}return &users.GetUserRes{UserList: tempList,}, nil }func main() {// ----------------------- 1. 注册consul服务 -----------------------// 1、初始化consul配置consulConfig := api.DefaultConfig()// consulConfig.Address = "127.0.0.1:8500" // consul服务的默认地址可省略,如果不是本机,需要补充// 2、获取consul操作对象consulClient, _ := api.NewClient(consulConfig)// 3、配置注册服务的参数agentService := api.AgentServiceRegistration {ID: "1", // 不要重复Tags: []string{"test"},Name: "UsersService",Port: port, // 和下面 grpc server 的配置相同, 否则就连接不上微服务Address: host, // 同上Check: &api.AgentServiceCheck{TCP: address,Timeout: "5s",Interval: "30s",},}// 4、注册服务到consul上consulClient.Agent().ServiceRegister(&agentService)// ----------------------- 2. 注册GRPC -----------------------// 1、获取Grpc示例grpcServer := grpc.NewServer()// 2、注册服务users.RegisterUsersServer(grpcServer, &Users{})// 3、监听端口listener, err := net.Listen("tcp", address)if err != nil {fmt.Println(err)}// 4、退出服务的时候关闭监听defer listener.Close()// 5、启动服务grpcServer.Serve(listener) }
-
主要关注 main 函数中,注册consul服务相关代码
-
重新处理依赖 $
go mod tidy
-
运行起来 $
go run main.go
-
刷新发现 127.0.0.1:8500 这个 consul 注册中心面板出来了一个新的服务
4 )处理 client
-
新建 demo/client/main.go
package mainimport ("fmt""protos/users""context""strconv""google.golang.org/grpc""google.golang.org/grpc/credentials/insecure""github.com/hashicorp/consul/api" )func main() {// ------------------------------- 1. 初始化 consul 客户端 -------------------------------// 1、初始化 consul 配置consulConfig := api.DefaultConfig()// consulConfig.Address = "127.0.0.1:8500" // 默认consul服务的地址,如有改变,重新指定// 2、获取consul操作对象consulClient, _ := api.NewClient(consulConfig)// ------------------------------- 2. 基于consul解析UserService的address -------------------------------usersServiceEntry, _, _ := consulClient.Health().Service("UsersService", "test", false, nil)usersServicePtr := usersServiceEntry[0].Service // service 指针对象userAddress := usersServicePtr.Address + ":" + strconv.Itoa(usersServicePtr.Port)// ------------------------------- 3. 基于GRPC连接和调用 -------------------------------// 1、建立连接userGrpcClient, err := grpc.Dial(userAddress, grpc.WithTransportCredentials(insecure.NewCredentials()))if err != nil {fmt.Println(err)}// 2、注册客户端userClient := users.NewUsersClient(userGrpcClient)// 3. 调用接口1:增加用户res1, _ := userClient.AddUser(context.Background(), &users.AddUserReq {User: &users.UsersModel {Name: "测试",Age: 20,},})fmt.Println(res1)fmt.Println()// 4. 调用接口2:获取数据res2, _ := userClient.GetUser(context.Background(), &users.GetUserReq{})fmt.Println(res2.UserList)// ------------------------------- 4. 以上完成了 users 服务的调用,如果需要调用其他服务,仍需重复步骤2,获取其他服务的入口,再次进行步骤3处理 TODO ------------------------------- }
-
以上的调用,可以进行适当的封装来满足不同业务的调用,仅供演示
-
当然结合数据库操作封装功能完成闭环调用,不再赘述
-
在 demo/client 下执行 $
go mod tidy
-
运行起来,$
go run main.go
发现服务端,客户端控制台都打印输出出来了