前言
Consul 是一个服务网格解决方案,提供具有服务发现、配置和分段功能的全功能控制平面。这些功能中的每一个都可以根据需要单独使用,也可以一起使用来构建完整的service mesh
。
安转Consul和Fabio
我这里采用本地运行的方式
运行consul
1
./consul.exe agent -dev
web页面地址
localhost:8500
运行Fabio
注意此处的端口号及协议类型
1
./fabio-1.6.0-windows_amd64.exe -proxy.addr ':10000;proto=grpc'
web 页面地址
http://localhost:9998/
gRPC服务端
golang代码如下,其中要注意的点:1、
registrationInfo.ID
不能重复;2、registrationInfo.Tags
需要有前缀才能被Fabio代理,以及协议要与前面启动Fabio处要对应;3、registrationInfo.Check
需要添加,因为Fabio只对健康检测通过的服务进行监控1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
package main import ( "context" "encoding/json" "flag" "fmt" "log" "net" pb "google.golang.org/grpc/examples/helloworld/helloworld" "github.com/hashicorp/consul/api" "google.golang.org/grpc" ) var ( port *int client *api.Client serverId string ) // server is used to implement helloworld.GreeterServer. type server struct { pb.UnimplementedGreeterServer port int } type Resp struct { Port int `json:"port"` Name string `json:"name"` } // SayHello implements helloworld.GreeterServer func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { resp, _ := json.Marshal( Resp{ Port: s.port, Name: in.GetName(), }) return &pb.HelloReply{Message: string(resp)}, nil } func main() { defer client.Agent().ServiceDeregister(serverId) lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port)) if err != nil { log.Fatalf("failed to listen: %v", err) } s := grpc.NewServer() pb.RegisterGreeterServer(s, &server{port: *port}) log.Printf("server listening at %v", lis.Addr()) if err := s.Serve(lis); err != nil { log.Fatalf("failed to serve: %v", err) } } func init() { port = flag.Int("port", 50051, "The server port") flag.Parse() serverId = fmt.Sprintf("gRPC_id_%d", *port) Registration(*port) } func Registration(port int) { var err error client, err = api.NewClient(api.DefaultConfig()) if err != nil { panic(err) } //注册信息 registrationInfo := api.AgentServiceRegistration{ ID: serverId, Name: "gRPCServer", Port: port, Tags: []string{"urlprefix-/", "proto=grpc"}, Address: "192.168.1.103", Check: &api.AgentServiceCheck{ CheckID: fmt.Sprintf("gRPCServerCheck:%d", port), TCP: fmt.Sprintf("192.168.1.103:%d", port), Interval: "2s", Timeout: "5s", }, } if err = client.Agent().ServiceRegister(®istrationInfo); err != nil { log.Fatalf("ServiceRegister error:%s", err.Error()) } }
在三个终端运行服务
1 2 3
go run main.go -port=50001 go run main.go -port=50002 go run main.go -port=50003
运行效果 在consul中,可以看到有一个名为
gRPCServer
的服务,该服务下有三个示例 在Fabio中的Routing Table
如图:
gRPC客户端
- golang代码如下,请求的端口为启动Fabio中处的端口,(即10000)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
package main import ( "context" "encoding/json" "fmt" "log" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" pb "google.golang.org/grpc/examples/helloworld/helloworld" ) func main() { numMap := map[int]int{ 50001: 0, 50002: 0, 50003: 0, } for i := 0; i < 1000; i++ { respPort := Request(10000) numMap[respPort]++ } log.Println("numMap: ", numMap) } func Request(port int) int { addr := fmt.Sprintf("192.168.1.103:%d", port) conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { log.Fatalf("did not connect: %v", err) } //resolver.SetDefaultScheme() defer conn.Close() c := pb.NewGreeterClient(conn) r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: "myName"}) if err != nil { log.Fatalf("could not greet: %s", err.Error()) } //log.Printf("resp: %s", r.GetMessage()) resp := new(Resp) _ = json.Unmarshal([]byte(r.GetMessage()), resp) return resp.Port } type Resp struct { Port int `json:"port"` Name string `json:"name"` }
- 运行及结果这里统计了各示例被请求的次数,结果与Fabio中各实例的权重相呼应
1 2
go run main.go 2022/06/30 01:38:56 numMap: map[50001:339 50002:326 50003:335]
个人总结
consul相对于之前使用过的zookeeper来说,在服务发现这部分的配置会相对简单,且包含了健康检查。对于客户端来说,不需要拉取服务端列表到本地并进行故障处理和负载均衡,请求的是Fabio代理