Use ETCD As Service Discovery And Register In Micro Server System

Use ETCD As Service Discovery And Register In Micro Server System

ETCD

  • ==官方Overview==:

etcd是一个分布式键值存储,它提供了一种可靠的方式来存储跨机器集群的数据。 它是开源的,可以在GitHub上找到。 etcd优雅地处理网络分区期间的领导选举,并容忍包括领导者在内的机器故障。
您的应用程序可以读取和写入数据到etcd。 一个简单的用例是将数据库连接详细信息或功能标志作为关键值对存储在etcd中。 可以监视这些值,允许您的应用在更改时自行重新配置。
高级应用程序利用一致性保证来实现数据库领导者选举或对整群工作人员进行分布式锁定

grpc

  • ==官方Overview==:

在 gRPC 里客户端应用可以像调用本地对象一样直接调用另一台不同的机器上服务端应用的方法,使得您能够更容易地创建分布式应用和服务。与许多 RPC 系统类似,gRPC 也是基于以下理念:定义一个服务,指定其能够被远程调用的方法(包含参数和返回类型)。在服务端实现这个接口,并运行一个 gRPC 服务器来处理客户端调用。在客户端拥有一个存根能够像服务端一样的方法

Usage

大致思路:

  1. 搭建etcd单点服务或者集群(方法不在这里赘述)
  2. 搭建grpc环境(grpc的使用方式不在这里赘述)
  3. 将服务注册到etcd中
  4. client从etcd中获取服务的调用地址

==etcd是一个键值对存储系统,我们可以大理解为,我们要把服务提供者的信息存贮到etcd中,然后我们的服务需求者会从etcd中获得这个服务的调用地址或者其他信息。==

或许会问键值对存储的话以及监听服务 Redis也可以做到。是的只从功能上来考虑的话,Redis也可以做到。但是etcd的集群概念与Redis的集群概念是不同的。可以说etcd的集群具有很强的容灾。它使用raft集群共识算法,只要有查过半数的节点存活,他就可以正产工作。

代码

我们使用go语言来实现,幸运的是对于ETCD的操作已经有优秀的开源项目https://github.com/micro/go-micro对其实现了封装。我就坐享其成了

test_demo.proto

1
2
3
4
5
6
7
8
9
10
11
12
13
14
syntax = "proto3";
service Greeter {
rpc Hello(HelloRequest) returns (HelloResponse) {}
}
message HelloRequest {
string name = 1;
}
message HelloResponse {
string greeting = 2;
}
protoc --proto_path=$GOPATH/src:. --micro_out=. --go_out=. path/to/greeter.proto

然后写 serever

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
package main
import (
"context"
"fmt"
"github.com/micro/go-micro"
proto "go_mricro_demo/proto"
"github.com/micro/go-plugins/registry/etcdv3"
)
type Greeter struct{}
func (g *Greeter) Hello(ctx context.Context, req *proto.HelloRequest, rsp *proto.HelloResponse) error {
rsp.Greeting = "Hello " + req.Name
println("Hello "+req.Name)
return nil
}
func main() {
// Create a new service. Optionally include some options here.
registry := etcdv3.NewRegistry()
service := micro.NewService(
micro.Name("greeter"),
micro.Registry(registry),
)
// Init will parse the command line flags.
service.Init()
// Register handler
proto.RegisterGreeterHandler(service.Server(), new(Greeter))
// Run the server
if err := service.Run(); err != nil {
fmt.Println(err)
}
}

then clent.go

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
package main
import (
"context"
"fmt"
"github.com/micro/go-micro"
proto "go_mricro_demo/proto"
"github.com/micro/go-plugins/registry/etcdv3"
)
func main() {
// Create a new service. Optionally include some options here.
registry := etcdv3.NewRegistry()
service := micro.NewService(micro.Name("greeter.client"), micro.Registry(registry), )
service.Init()
// Create new greeter client
greeter := proto.NewGreeterService("greeter", service.Client())
// Call the greeter
rsp, err := greeter.Hello(context.TODO(), &proto.HelloRequest{Name: "John"})
if err != nil {
fmt.Println(err)
}
// Print response
fmt.Println(rsp.Greeting)
}

我们可以修改server之后多启动几个,至少两个这样才能看出多个服务调用分配的效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
client go run client.go
Hello John
➜ client
➜ client go run client.go
Hello John
➜ client go run client.go
Hello John
➜ client go run client.go
Hello John
➜ client go run client.go
Hello John
➜ client go run client.go
Hello John
➜ client go run client.go
Hello John
➜ client go run client.go
Hello John
➜ client go run client.go
Hello John
➜ client go run client.go
Hello John
➜ client go run client.go
Hello John

server1:

1
2
3
4
5
6
7
8
9
10
11
12
13
➜ server go run main.go
2018-06-22 09:39:42.653195 I | Listening on [::]:49723
2018-06-22 09:39:42.653275 I | Broker Listening on [::]:49724
2018-06-22 09:39:42.653449 I | Registering node: greeter-22b75c2a-75bd-11e8-9c01-787b8ac71eb9
John
John
John
John
John
John
John
John
John

server2:

1
2
3
4
5
6
7
8
9
10
➜ server go run main.go
2018-06-22 09:44:10.930931 I | Listening on [::]:49846
2018-06-22 09:44:10.931027 I | Broker Listening on [::]:49847
2018-06-22 09:44:10.931118 I | Registering node: greeter-c29f4bd0-75bd-11e8-9c87-787b8ac71eb9
Hello John
Hello John
Hello John
Hello John
Hello John
Hello John

致此一个demo就完成了。

溜了溜了