Регистрация и обнаружение служб часто используются в архитектуре распределенных служб.В число широко используемых в отрасли инструментов регистрации и обнаружения служб входят:ZooKeeper,etcd,ConsulиEureka. Основными функциями Consul являются обнаружение служб, проверка работоспособности, хранение KV, безопасная служебная связь и несколько центров обработки данных. Различия между Consul и некоторыми другими инструментами можно посмотреть здесь.Consul vs. Other Software.
Зачем нужна регистрация службы и обнаружение службы?
Предполагая, что в распределенной системе есть две службы Service-A (далее «SA») и Service-B (далее «SB»), когда SA хочет вызвать SB, мы сначала думаем о непосредственно в SA Запросите IP-адрес и порт прослушивания сервера, на котором расположен SB. Нет проблем, когда масштаб службы мал, но есть некоторые проблемы, когда масштаб службы велик и для каждой службы развернуто более одного экземпляра, например поскольку SB развернула три экземпляра SB-1, SB-2 и SB-3.В настоящее время SA хочет позвонить SB, какой IP-адрес экземпляра службы следует запросить? Или прописать IP-адреса трех экземпляров службы в коде S-A и выбирать один из IP-адресов каждый раз, когда вызывается S-B? Это кажется очень негибким, и тогда мы подумалиNginx
Достаточно, чтобы очень хорошо решить эту проблему, ввестиNginx
После того, как текущая структура стала следующей:
В этой схеме:
- Во-первых, после запуска экземпляра S-B он регистрирует свою собственную служебную информацию (в основном IP-адрес и номер порта, на котором находится служба) в инструменте регистрации. Способы регистрации разных сервисов инструментальных средств регистрации различаются, конкретный способ регистрации Консула будет описан далее.
- После того как служба зарегистрирует информацию о службе с помощью средства регистрации, средство регистрации может выполнить проверку работоспособности службы, чтобы определить, какие экземпляры службы доступны, а какие недоступны.
- После запуска S-A он может получить IP-адреса и порты всех работоспособных экземпляров S-B с помощью инструментов регистрации служб и обнаружения служб и поместить эту информацию в свою собственную память, а S-A может использовать эту информацию для вызова S-B.
- S-A может обновлять служебную информацию S-B, хранящуюся в памяти, наблюдая за инструментом регистрации. Например, если S-B-1 зависнет, механизм проверки работоспособности пометит его как недоступный, такие изменения информации будут отслеживаться S-A, и S-A будет обновлять служебную информацию S-B-1 в своей памяти.
Таким образом, в дополнение к функциям регистрации и обнаружения самой службы, инструменты регистрации и обнаружения службы нуждаются как минимум в функциях проверки работоспособности и уведомления об изменении состояния.
Consul
Как инструмент распределенного обслуживания, Консул часто развертывается в кластере, чтобы избежать единой точки отказа.Узлы кластера Консул делятся на два типа: Сервер и Клиент (все узлы также называются Агентами).Узел Сервер сохраняет Узел-клиент отвечает за проверку работоспособности и пересылку запросов данных на сервер; узел-сервер имеет узел-лидер и несколько узлов-последователей, узел-лидер будет синхронизировать данные с узлом-ведомым, а когда узел-лидер зависнет, он запустится. механизм выборов для создания нового Лидера.
Клиентский узел очень легкий и не имеет состояния.Он перенаправляет запросы на чтение и запись на серверный узел с помощью RPC, а также может напрямую отправлять запросы на чтение и запись на серверный узел. Ниже представлена диаграмма архитектуры Consul:
Установка Consule и конкретное использование, а также другие детали можно просмотретьофициальная документация. Ниже показано, как я использовал Docker для создания кластера Consul с 3 узлами сервера и 1 узлом клиента.# 这是第一个 Consul 容器,其启动后的 IP 为172.17.0.5
docker run -d --name=c1 -p 8500:8500 -e CONSUL_BIND_INTERFACE=eth0 consul agent --server=true --bootstrap-expect=3 --client=0.0.0.0 -ui
docker run -d --name=c2 -e CONSUL_BIND_INTERFACE=eth0 consul agent --server=true --client=0.0.0.0 --join 172.17.0.5
docker run -d --name=c3 -e CONSUL_BIND_INTERFACE=eth0 consul agent --server=true --client=0.0.0.0 --join 172.17.0.5
#下面是启动 Client 节点
docker run -d --name=c4 -e CONSUL_BIND_INTERFACE=eth0 consul agent --server=false --client=0.0.0.0 --join 172.17.0.5
Переменные среды, указанные при запуске контейнераCONSUL_BIND_INTERFACE
По сути, это эквивалентно указанию времени запуска Консула.--bind
Переменные параметры, например, можно заменить команду запуска контейнера c1 на следующую, и будет достигнут тот же эффект.
docker run -d --name=c1 -p 8500:8500 -e consul agent --server=true --bootstrap-expect=3 --client=0.0.0.0 --bind='{{ GetInterfaceIP "eth0" }}' -ui
Управляйте Консулом с помощьюCommandsиHTTP APIДва способа, введите любой контейнер для выполненияconsul members
Вы можете получить следующий вывод, указывающий, что кластер Consul был успешно построен.
Node Address Status Type Build Protocol DC Segment
2dcf0c824cf0 172.17.0.7:8301 alive server 1.4.4 2 dc1 <all>
64746cffa116 172.17.0.6:8301 alive server 1.4.4 2 dc1 <all>
77af7d94a8ca 172.17.0.5:8301 alive server 1.4.4 2 dc1 <all>
6c71148f0307 172.17.0.8:8301 alive client 1.4.4 2 dc1 <default>
Кодекс Практика
Предположим теперь, что есть сервисный узел-сервер, написанный на Node.js, которому нужно передатьgRPCспособ вызвать сервис go-server, написанный на Go.
Ниже приведен файл службы и типа данных, определенный с помощью Protobuf.hello.proto
.
syntax = "proto3";
package hello;
option go_package = "hello";
// The greeter service definition.
service Greeter {
// Sends a greeting
rpc SayHello (stream HelloRequest) returns (stream HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
Используйте команду для генерации кода Go из определения Protobuf:protoc --go_out=plugins=grpc:./hello ./*.proto
Вы получите файл hello.pb.go в каталоге hello, а затем реализуете службу RPC, которую мы определили в файле hello.go.
// hello.go
package hello
import "context"
type GreeterServerImpl struct {}
func (g *GreeterServerImpl) SayHello(c context.Context, h *HelloRequest) (*HelloReply, error) {
result := &HelloReply{
Message: "hello" + h.GetName(),
}
return result, nil
}
Ниже находится входной файлmain.go
, в основном для регистрации службы, которую мы определили, в gRPC и создания/ping
Интерфейс используется для последующих проверок работоспособности Консула.
package main
import (
"go-server/hello"
"google.golang.org/grpc"
"net"
"net/http"
)
func main() {
lis1, _ := net.Listen("tcp", ":8888")
lis2, _ := net.Listen("tcp", ":8889")
grpcServer := grpc.NewServer()
hello.RegisterGreeterServer(grpcServer, &hello.GreeterServerImpl{})
go grpcServer.Serve(lis1)
go grpcServer.Serve(lis2)
http.HandleFunc("/ping", func(res http.ResponseWriter, req *http.Request){
res.Write([]byte("pong"))
})
http.ListenAndServe(":8080", nil)
}
На данный момент весь код на стороне go-server написан, видно, что в коде нет ничего связанного с Консулом, использовать Консул для регистрации сервиса можно без какого-либо вмешательства в код проекта. Следующее, что нужно сделать, это зарегистрировать go-server в Consul. Зарегистрировать сервис в Consul можно, напрямую вызвав REST API, предоставляемый Consul, а также есть конфигурационный файл, не навязчивый для проекта. Детали файла конфигурации сервиса Consul можно посмотретьПроверьте это здесь. Ниже приведен файл конфигурации для регистрации нашего сервиса через файл конфигурацииservices.json
:
{
"services": [
{
"id": "hello1",
"name": "hello",
"tags": [
"primary"
],
"address": "172.17.0.9",
"port": 8888,
"checks": [
{
"http": "http://172.17.0.9:8080/ping",
"tls_skip_verify": false,
"method": "GET",
"interval": "10s",
"timeout": "1s"
}
]
},{
"id": "hello2",
"name": "hello",
"tags": [
"second"
],
"address": "172.17.0.9",
"port": 8889,
"checks": [
{
"http": "http://172.17.0.9:8080/ping",
"tls_skip_verify": false,
"method": "GET",
"interval": "10s",
"timeout": "1s"
}
]
}
]
}
в файле конфигурации172.17.0.9
Представляет IP-адрес сервера, на котором расположен go-server,port
Это другой порт, который служба прослушивает.check
Частью определения является проверка работоспособности, которую Консул запрашивает каждые 10 секунд./ping
Интерфейс использует это, чтобы определить, исправна ли служба. Скопируйте этот файл конфигурации в каталог /consul/config контейнера c4 и выполнитеconsul reload
После команды сервис hello в конфигурационном файле регистрируется у Consul. путем выполнения на хостеcurl http://localhost:8500/v1/catalog/services\?pretty
Вы можете увидеть приветственный сервис, который мы зарегистрировали.
Вот код службы node-server:
const grpc = require('grpc');
const axios = require('axios');
const protoLoader = require('@grpc/proto-loader');
const packageDefinition = protoLoader.loadSync(
'./hello.proto',
{
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true
});
const hello_proto = grpc.loadPackageDefinition(packageDefinition).hello;
function getRandNum (min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
};
const urls = []
async function getUrl() {
if (urls.length) return urls[getRandNum(0, urls.length-1)];
const { data } = await axios.get('http://172.17.0.5:8500/v1/health/service/hello');
for (const item of data) {
for (const check of item.Checks) {
if (check.ServiceName === 'hello' && check.Status === 'passing') {
urls.push(`${item.Service.Address}:${item.Service.Port}`)
}
}
}
return urls[getRandNum(0, urls.length - 1)];
}
async function main() {
const url = await getUrl();
const client = new hello_proto.Greeter(url, grpc.credentials.createInsecure());
client.sayHello({name: 'jack'}, function (err, response) {
console.log('Greeting:', response.message);
});
}
main()
Адрес 172.17.0.5 в коде это IP адрес контейнера c1.В проекте node-server адрес сервиса hello получается напрямую через API предоставляемый Консулом.После получения сервиса нам нужно отфильтровать из адреса исправной службы, а затем случайным образом получить адрес из всех Выберите один из адресов для вызова. Мониторинга Consul в коде нет, реализация мониторинга может отфильтровывать адрес службы здоровья, постоянно опрашивая API выше для обновленияurls
массив, чтобы сделать это. Теперь запустите node-server, чтобы вызвать службу go-server.
Регистрация и обнаружение сервисов привносят в сервисы возможности динамического масштабирования, а также в определенной степени усложняют архитектуру. Помимо обнаружения и регистрации сервисов, Consul также имеет множество приложений в центрах конфигурации и распределенных блокировках.