etcd学习和实战:2、本地集群测试及gRPC命名和发现
文章目录
1. 前言
前面我们已经简单了解并安装了etcd,由于etcd的应用场景较多,我这里只针对我目前使用的场景进行深入学习和总结,我们的使用场景之前已经说过了,主要是使用etcd的服务注册发现功能,这里我们先利用官网的开发者指南搭建本地集群用于后续测试,然后看下如何将gRPC和etcd结合用于发现gRPC服务。
2. 搭建集群
这里主要是根据:https://etcd.io/docs/v3.4/dev-guide/local_cluster/的内容,所以如果版本不同或者存在一些问题的话,可以去官网的开发者文档中找关于本地集群相关的内容或者issue相关内容进行参考解决。
2.1 本地独立集群
这个就是上节我们安装的单个etcd程序,启动集群则直接运行编译安装后的程序即可:
/tmp/test-etcd/etcd
正在运行的 etcd 成员侦听localhost:2379客户端请求。
之后我们在不写客户端程序的情况下可以直接使用etcdctl这个命令行程序作为客户端进行简单的key-value读写确认集群正常工作:
2.2 本地多成员集群
- 安装goreman
Procfile在ETCD git仓库的基座被设置成很容易地配置一个本地多构件集群。要启动多成员集群,请导航到 etcd 源代码树的根目录并执行以下操作:
cd $HOME/etcd
go get github.com/mattn/goreman
- 设置环境变量
设置环境变量,把$GOPATH/bin也加入环境变量,由go get安装的包的可执行程序默认会放在对应目录下,所以我们安装的goreman不添加路径执行的话需要设置这一步,一般来说当我们通过go mod管理go相关包时需要设置该环境变量:
echo 'export PATH=$PATH:$GOPATH/bin' >> ~/.bashrc
source ~/.bashrc
- 利用goreman使用etcd的Procfile启动集群
goreman -f Procfile start
3. 与集群交互
3.1 打印成员列表
etcdctl --write-out=table --endpoints=localhost:2379 member list
3.2 存储示例键值对
在集群中存储一个键值对:
$ etcdctl put foo bar
OK
如果打印OK,则表示键值对存储成功。
4. 测试容错
要行使 etcd 的容错能力,请杀死一个成员并尝试检索key。
-
标识要停止的成员的进程名称。
在
Procfile
列出了多构件簇的性质。例如,考虑进程名称为 的成员etcd2
。 -
停止成员:
# kill etcd2 $ goreman run stop etcd2
-
存储key:
$ etcdctl put key hello OK
-
检索上一步中存储的key:
$ etcdctl get key hello
-
从停止的成员中检索key:
$etcdctl --endpoints=localhost:22379 get key
该命令应显示由连接失败引起的错误:
{"level":"warn","ts":"2021-06-02T17:34:17.210+0800","caller":"clientv3/retry_interceptor.go:62","msg":"retrying of unary invoker failed","target":"endpoint://client-9a0c0666-5e94-403d-b31e-0396b627387e/localhost:22379","attempt":0,"error":"rpc error: code = DeadlineExceeded desc = latest balancer error: all SubConns are in TransientFailure, latest connection error: connection error: desc = \"transport: Error while dialing dial tcp 127.0.0.1:22379: connect: connection refused\""} Error: context deadline exceeded
-
重启停止的成员:
$goreman run restart etcd2
-
从重新启动的成员获取密钥:
$ etcdctl --endpoints=localhost:22379 get key hello
重新启动成员重新建立连接。
etcdctl
现在将能够成功检索密钥。要了解有关与 etcd 交互的更多信息,请阅读与 etcd 交互部分。
5. gRPC命名和发现
go-grpc:用于使用 etcd 后端解析 gRPC 端点
etcd 提供了一个 gRPC 解析器来支持替代名称系统,该系统从 etcd 获取端点以发现 gRPC 服务。底层机制基于监视以服务名称为前缀的键的更新。
5.1 在go-grpc中使用etcd发现
etcd 客户端提供了一个 gRPC 解析器,用于使用 etcd 后端解析 gRPC 端点。解析器使用 etcd 客户端初始化,并给出解析目标:
import (
"go.etcd.io/etcd/clientv3"
etcdnaming "go.etcd.io/etcd/clientv3/naming"
"google.golang.org/grpc"
)
...
cli, cerr := clientv3.NewFromURL("http://localhost:2379")
r := &etcdnaming.GRPCResolver{Client: cli}
b := grpc.RoundRobin(r)
conn, gerr := grpc.Dial("my-service", grpc.WithBalancer(b), grpc.WithBlock(), ...)
5.2 管理服务端点
etcd 解析器将解析目标前缀下的所有key(例如,“my-service/”)和 JSON 编码的 go-grpcnaming.Update值视为潜在的服务端点。端点通过创建新的键并通过删除键从服务中删除。
5.2.1 添加端点
可以通过以下方式将新端点添加到服务中etcdctl
:
ETCDCTL_API=3 etcdctl put my-service/1.2.3.4 '{"Addr":"1.2.3.4","Metadata":"..."}'
etcd 客户端的GRPCResolver.Update
方法还可以使用匹配的key注册新端点Addr
:
r.Update(context.TODO(), "my-service", naming.Update{Op: naming.Add, Addr: "1.2.3.4", Metadata: "..."})
5.2.2 删除端点
可以通过以下方式从服务中删除主机etcdctl
:
ETCDCTL_API=3 etcdctl del my-service/1.2.3.4
etcd 客户端的GRPCResolver.Update
方法也支持删除端点:
r.Update(context.TODO(), "my-service", naming.Update{Op: naming.Delete, Addr: "1.2.3.4"})
5.2.3 使用租约注册端点
使用租约注册端点可确保如果主机无法维持保持活动的心跳(例如,其机器出现故障),它将从服务中删除:
lease=`ETCDCTL_API=3 etcdctl lease grant 5 | cut -f2 -d' '`
ETCDCTL_API=3 etcdctl put --lease=$lease my-service/1.2.3.4 '{"Addr":"1.2.3.4","Metadata":"..."}'
ETCDCTL_API=3 etcdctl lease keep-alive $lease
6. 最后
到这里我们应该已经知道如何利用etcd来处理gRPC服务的发现和管理了,接下来我们将分别用Java和go写一些测试的gRPC服务然后和我们搭建的etcd集群结合起来进行测试。