Перейти к содержанию

Именование и обнаружение gRPC

go-grpc: разрешение конечных точек gRPC с бэкендом etcd

etcd предоставляет резолвер gRPC для альтернативной системы имён, которая получает конечные точки из etcd при обнаружении служб gRPC. Механизм основан на наблюдении за обновлениями ключей с префиксом имени службы.

Эта возможность является экспериментальной, поскольку зависит от пакета google.golang.org/grpc/resolver , который всё ещё считается экспериментальным в grpc-go.

Использование обнаружения etcd с go-grpc

Клиент etcd предоставляет резолвер gRPC для разрешения конечных точек gRPC с бэкендом etcd. Резолвер инициализируется клиентом 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"}'

Метод endpoints.Manager клиента etcd также может зарегистрировать новую конечную точку с ключом, соответствующим 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

Метод endpoints.Manager клиента etcd также поддерживает удаление конечных точек:

em := endpoints.NewManager(client, "foo/bar/my-service")
err := em.DeleteEndpoint(context.TODO(), "foo/bar/my-service/e1")

Регистрация конечной точки с арендой

Регистрация конечной точки с арендой гарантирует её удаление из службы, если узел не сможет поддерживать heartbeat keepalive, например из-за отказа машины:

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

В Golang:

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"})})