vlambda博客
学习文章列表

go+protobuf+grpc+consul简单的服务发现模型

一  环境准备

  • windows64 (此处我用的windows,建议大家linux)

  • 安装consul,请自行搜索

  • 安装protobuf,请自行搜索 

二  概念梳理

  • consul 是服务发现工具,简单地说,就是各个server将自己注册到consul上,client不再记住各个server的ip+port,而是去consul上获取想要连接的server。使得server对client不再需要暴露,可以动态伸缩。

  • protobuf 可以拿来和xml、json对比,都是数据格式,只是protobuf更加轻量级,适合做微服务或者tcp通信。使用起来相对繁琐一点点。

  • rpc 可以对比ipc(进程间通信),它是各个服务间的通信,重点在r和i的区别,rpc是远程调用。

  • grpc 是rpc的一种,它是进阶版,更高效,基于http2(可以双工通信),默认采用protobuf格式的数据

三  实现过程

  3.1 目录结构

      

  • 项目名称test_grpc_consul

  • pb目录为存放protobuf文件

  • person.proto为源生protobuf代码

  • person.pb.go为编译打包出的能为go调用的代码

  • consul-server.go为server程序,实现了往consul的注册和服务的监听

  • consul-client.go为client程序,实现了从consul查找server并发起调用

  • consul-deregister为一个管理程序,实现了consul中server的注销

  3.2 protobuf的生成

    person.proto

 1 syntax = "proto3";
2
3 package pb;
4 option go_package = "./;pb"; //此处我也不知道干嘛用的,不加他报错,网上搜索的解决方案
5
6 message Person{
7 string name = 1;
8 int32 age = 2;
9 }
10
11 //添加rpc服务
12 service hello{
13 rpc sayHello(Person) returns (Person);
14
15 }

    将person.proto编译打包

先cd到pb目录,再执行以下命令    

protoc --go_out=plugins=grpc:./ *.proto

生成person.pb.go文件

 

其实golang中,一般的rpc中proto的打包为以下命令:

protoc --go_out=./ *.proto

 

  3.3 server程序

package main

import (
"context"
"fmt"
"/test_grpc_consul/pb" //你们自己的路径
"github.com/hashicorp/consul/api"
"google.golang.org/grpc"
"net"
)
type Children
struct {

}
func (
this *Children)SayHello(ctx context.Context,p *pb.Person) (*pb.Person,error){
p.Name
= "hello "+p.Name
return p,nil
}
func main(){
//把grpc服务注册到consul上
//初始化consul配置
consulConfig := api.DefaultConfig()
//创建consul对象
consulClient,err := api.NewClient(consulConfig)
if err!=nil{
fmt.Println(
"server, api.newclient err:",err)
return
}
//告诉consul,即将注册的服务的配置信息
reg := api.AgentServiceRegistration{
Kind:
"",
ID:
"wbw1_id",
Name:
"wbw001_grpc_consul",
Tags: []
string{"wbw1","asa1"},
Port:
8800,
Address:
"127.0.0.1",
TaggedAddresses: nil,
EnableTagOverride:
false,
Meta: nil,
Weights: nil,
Check:
&api.AgentServiceCheck{
CheckID:
"wbw1_id_check",
Name:
"",
Args: nil,
DockerContainerID:
"",
Shell:
"",
Interval:
"5s",
Timeout:
"1s",
TTL:
"",
HTTP:
"",
Header: nil,
Method:
"",
Body:
"",
TCP:
"127.0.0.1:8800",
Status:
"",
Notes:
"",
TLSServerName:
"",
TLSSkipVerify:
false,
GRPC:
"",
GRPCUseTLS:
false,
AliasNode:
"",
AliasService:
"",
SuccessBeforePassing:
0,
FailuresBeforeCritical:
0,
DeregisterCriticalServiceAfter:
"",
},
Checks: nil,
Proxy: nil,
Connect: nil,
Namespace:
"",
}
//注册gprc服务到consul上
consulClient.Agent().ServiceRegister(&reg)
grpcServer :
= grpc.NewServer()
pb.RegisterHelloServer(grpcServer,
new(Children))
listener,err :
= net.Listen("tcp", "127.0.0.1:8800")
if err != nil{
fmt.Println(
"listen err:",err)
}
defer listener.Close()
grpcServer.Serve(listener)
}

  3.4 client程序

package main

import (
"context"
"fmt"
"/test_grpc_consul/pb" //同server此处
"github.com/hashicorp/consul/api"
"google.golang.org/grpc"
"strconv"
)
func main(){
consulConfig :
= api.DefaultConfig()
conculClient,err :
= api.NewClient(consulConfig)
if err!=nil{
fmt.Println(
"client, api.newclient err:",err)
return
}
services,_,err :
= conculClient.Health().Service("wbw001_grpc_consul","wbw1",true,nil )
addr :
= services[0].Service.Address+":"+strconv.Itoa(services[0].Service.Port)

//grpcConn,err := grpc.Dial("127.0.0.1:8800",grpc.WithInsecure())
grpcConn,err := grpc.Dial(addr,grpc.WithInsecure())
if err != nil{
fmt.Println(
"dial err:",err)
}
defer grpcConn.Close()

grpcClient :
= pb.NewHelloClient(grpcConn)

var person pb.Person
person.Name
= "wbw"
person.Age
= 18
p,err :
= grpcClient.SayHello(context.TODO(),&person)
fmt.Println(p,err)
}

  3.5 server注销程序

package main

import (
"fmt"
"github.com/hashicorp/consul/api"
)

func main(){
consulConfig :
= api.DefaultConfig()
consulClient,err :
= api.NewClient(consulConfig)
if err != nil{
fmt.Println(
"deregister, api.newclient err:",err)
return
}

consulClient.Agent().ServiceDeregister("wbw1_id")
}

四  调用说明

  4.1 启动 consul

//本文请用
consul agent -dev

//但是生产环境建议用
// consul agent -server -bootstrap-expect 1 -data-dir D:\tools\consul_1.10.0_windows_amd64\data_dir\ -node=n1 -bind=10.10.10.18 -ui -rejoin -config-dir=D:\tools\consul_1.10.0_windows_amd64\config_dir\ -client 0.0.0.0

我们进入网址http://localhost:8500/
可以发现我们的consul启动完成

go+protobuf+grpc+consul简单的服务发现模型

  4.2 启动server

先cd到test_grpc_consul目录,再执行以下命令    

go run consul-server.go

可以看到我们的服务已经执行了

然后进入网址http://localhost:8500/可以看到我们的服务已经成功注册到consul了,点进去还能看到健康检测正常

go+protobuf+grpc+consul简单的服务发现模型

  4.3 启动client

先cd到test_grpc_consul目录,再执行以下命令    

go run consul-client.go

调用成功!!!

  4.4 启动注销程序

先cd到test_grpc_consul目录,再执行以下命令    

go run consul-deregister.go

 

 

 我们可以看到该server已经不再consul中了,同时我们调用client也会失败。

 

 注意:

 如果我们把client直连server,依然能成功,因为我们的server并没有退出,仅仅是在consul中抹掉了痕迹。

 

四  补充说明

  • 建议开启go mod,这样不依赖于gopath等路径,且不需要go get等操作,能利用goland自动拉取