文档版本 v3.7-DRAFT 处于 草稿 状态。如需获取最新的稳定版文档,请参阅 v3.6。
gRPC 命名与发现
go-grpc:用于通过 etcd 后端解析 gRPC 端点
etcd 提供了一个 gRPC 解析器,用于支持一种替代的命名系统,该系统从 etcd 中获取端点以发现 gRPC 服务。其底层机制基于监听以服务名称为前缀的键的更新。
请注意,此功能尚处于实验阶段,因为它依赖于 google.golang.org/grpc/resolver 包,而该包在 grpc-go 中仍处于实验阶段。
使用 etcd 发现功能与 go-grpc 配合
etcd 客户端提供了一个 gRPC 解析器,用于通过 etcd 后端解析 gRPC 端点。该解析器使用 etcd 客户端进行初始化:
import (
clientv3 "go.etcd.io/etcd/client/v3"
etcdnaming "go.etcd.io/etcd/client/v3/naming/resolver"
"google.golang.org/grpc"
)
...
cli, err := clientv3.NewFromURL("http://localhost:2379")
if err != nil {
// ...
}
r, err := etcdnaming.NewBuilder(cli)
if err != nil {
// ...
}
conn, gerr := grpc.NewClient("my-service", grpc.WithResolvers(r), ...)
管理服务端点
etcd 解析器将解析目标前缀下(例如 “foo/bar/my-service/”)所有以“/”开头的键,并将其值为 JSON 编码(历史上是 go-grpc 的 naming.Update)的条目视为潜在的服务端点。通过创建新键可向服务中添加端点,通过删除键可将端点从服务中移除。
添加一个端点
可以通过 etcdctl 向服务中添加新的端点:
ETCDCTL_API=3 etcdctl put foo/bar/my-service/1.2.3.4 '{"Addr":"1.2.3.4"}'
etcd 客户端的 endpoints.Manager 方法也可以使用与 Addr 匹配的键来注册新端点:
em := endpoints.NewManager(client, "foo/bar/my-service")
err := em.AddEndpoint(context.TODO(),"foo/bar/my-service/e1", endpoints.Endpoint{Addr:"1.2.3.4"})
当拨号连接包含多个端点的服务时,若希望启用轮询负载均衡,可以使用 grpc 内置的轮询负载均衡器来建立连接:
conn, gerr := grpc.NewClient("etcd:///foo", grpc.WithResolvers(etcdResolver),
grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy":"round_robin"}`))
删除一个端点
可以通过 etcdctl 从服务中删除主机:
ETCDCTL_API=3 etcdctl del foo/bar/my-service/1.2.3.4
etcd 客户端的 endpoints.Manager 方法也支持删除端点:
em := endpoints.NewManager(client, "foo/bar/my-service")
err := em.DeleteEndpoint(context.TODO(), "foo/bar/my-service/e1")
使用租约注册一个端点
使用租约注册端点可确保当主机无法维持心跳保活(例如机器故障)时,它将被自动从服务中移除:
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"}'
ETCDCTL_API=3 etcdctl lease keep-alive $lease
在 Go 语言中:
em := endpoints.NewManager(client, "foo/bar/my-service")
err := em.AddEndpoint(context.TODO(), "foo/bar/my-service/e1", endpoints.Endpoint{Addr:"1.2.3.4"})
原子性地更新端点
如果需要在单个事务中修改多个端点,可以直接使用 endpoints.Manager:
em := endpoints.NewManager(c, "foo")
err := em.Update(context.TODO(), []*endpoints.UpdateWithOpts{
endpoints.NewDeleteUpdateOpts("foo/bar/my-service/e1", endpoints.Endpoint{Addr: "1.2.3.4"}),
endpoints.NewAddUpdateOpts("foo/bar/my-service/e1", endpoints.Endpoint{Addr: "1.2.3.14"})})