Service Discovery вместе с Consul
С ростом популярности микросервисов количество backend-компонентов растёт, иногда в геометрической прогрессии, особенно когда одному микросервису нужна своя база данных, кэш-сервер и т.д. Когда инфраструктуры становится много, возникают новые проблемы, которые тоже приходится решать. Одной из таких проблем является деплой и конфигурация.
Подходов к решению этой проблемы существует множество, одним из них является использование service discovery на основе Consul.
Consul - децентрализованная отказоустойчивая система, позволяющая сервисам находить друг друга в сети. Кроме service discovery в Consul есть health checks, kv store, locks и несколько утилит, чтобы всё это максимально эффективно использовать.
Тем, кто не знаком, советую сходить на официальный сайт.
С точки зрения инфраструктуры Consul состоит из агента и сервера. По сути, это один бинарник, запущенный в разных режимах. Для защиты от splitbrain рекомендуется сервер запускать в количестве 3-5 инстансов.
Агенты же ставятся на каждую ноду с сервисом (например, в openvz контейнер). Таким образом, каждый сервис работает только с локальным агентом, располагающимся на порту 8500.
Консистентность обеспечивается за счёт того, что серверы общаются между собой по протоколу Raft, а клиенты — Gossip. В один конкретный момент времени есть только один Leader server, который принимает все запросы на запись и распространяет эту информацию по остальной сети. Вся остальная сеть, соответственно работает на чтение. Как очевидно, используется eventual consistency.
Что умеет Consul
Service discovery — сервисы регистрируются в каталоге и могут запрашивать информацию о расположении друг друга в сети.
Health checks — консул умеет получать информацию о состоянии сервисов c помощью http запросов, скриптов, tcp-соединения на порт, TTL. Так же поддерживаются проверки для gRPC сервисов и приложений внутри Docker контейнеров. При этом балансировка нагрузки будет производиться только на здоровые ноды.
Kv store — простое хранилище типа ключ-значение. Можно использовать, чтобы хранить конфигурацию, данные для координации сервисов между собой, и тд.
Sessions — механизм сессий позволяет реализовать локи и семафоры для сервисов. Подробнее в документации: сессии и семафоры.
Web ui — так как консул сравнивают со швейцарским ножом, логично было бы предположить, что у него есть классный UI. По-умолчанию, доступен по адресу http://localhost:8500/ui
(в dev окружении). Смотрите официальное live demo.
Для чего можно использовать
Service discovery с health checks
Собственно основная задача (для меня) - это service discrovery. Сюда же относится автоматическая балансировка запросов на живые ноды. Жизненный цикл сервиса выглядит так:
- Приложение регистрируется в каталоге, сообщая своё имя и порт.
- С помощью health checks производится проверка, что приложение работоспособно.
- Если приложение остановилось или упало, консул перестаёт балансировать на него нагрузку. В этот момент нода помечается как проблемная. По истечении определённого таймаута регистрация приложения удаляется. Актуальную информацию о проблемных нодах и их статусе, можно посмотреть в веб-интерфейсе.
Получить адрес и порт нужного сервиса клиенты могут с помощью HTTP Api или DNS запросов (консул поднимает свой DNS сервер на порту 8600). Как использовать http api можно прочитать здесь, а про DNS здесь.
Централизованное управление конфигурацией
Благодаря своему KV-store, Консул может выступать в роли центрального хранилища конфигурации для приложений. Работать это может двумя способами:
-
Если приложение конфигурируется через переменные окружения, то можно использовать утилиту envconsul, которая будет трансформировать ключи из KV хранилища в environment variables и запускать новый сервис. Это удобно тем, что при изменении конфигурации через consul ui, envconsul автоматически перезапустит нужный сервис.
-
Приложение может само ходить в консул и брать нужные настройки оттуда. Это может быть удобно для изменения поведения приложения в рантайме, например, с помощью feature-flags.
Конечно, можно смешивать оба подхода для получения большего профита.
Балансировка нагрузки между сервисами
Консул автоматически балансирует нагрузку только на живые ноды. Здесь же затрону момент, когда необходим реверс-прокси.
-
nginx. Для балансировки через nginx приходится прописывать апстримы в конфиг-файле. Чтобы не делать этого вручную можно использовать утилиту consul-template, которая по шаблону сгенерирует конфигурационный файл (автоматически при старте и изменении статуса нод) с нужными хостами и портами и перезагрузит nginx.
-
Для максимально ленивых есть fabio — load balancer для consul. Он умеет маршрутизировать запросы на живые ноды вообще без какой-либо конфигурации, автоматически. Всё, что нужно сделать, это добавить специальный тег для нужного сервиса, вот такого вида:
urlprefix-mysite.com/
. Помеченные таким тегом сервисы будут получать все запросы дляmysite.com/
.
Кроме HTTP, fabio умеет балансировать и TCP соединения.
Также можно балансировать нагрузку между сервисами в различных датацентрах (geo failover), подробнее по ссылке.
Локи
Благодаря локам, можно запускать N сервисов в один момент времени.
Например, у нас есть некий распределённый крон, который находится на 10 нодах. В этом кроне есть задача, которая должна работать в единственном числе один момент времени. Такое ограничение достаточно легко реализовать с помощью локов (подробнее в документации).
Вот пример, как запустить ровно один редис:
consul lock service/redis/lock redis-server
Как только редис крашнется, автоматически запустится инстанс на другой ноде.
Отдельным плюсом является то, что это не требует конфигурации, что на порядок упрощает деплой и вообще снижает когнитивную нагрузку.
Регистрация внешних сервисов
В экосистеме, построенной на Consul можно регистрировать и внешние сервисы, например, базу данных.
В качестве примера: есть два окружения — development и production. Сервисы в обоих этих окружениях зависят от одного и того же внешнего сервиса — базы данных, доступной по адресу database.service.consul
.
Соответственно, всё что нужно, это зарегистрировать нашу базу данных таким образом:
# Development curl -X PUT -d '{"name": "database", "port": 5432}' http://localhost:8500/v1/agent/service/register # Production curl -X PUT -d '{"name": "database", address: "db.production.com"}' http://localhost:8500/v1/agent/service/register
Как видно, в production окружении регистрируется база данных по адресу db.production.com
. Кстати, чтобы резолвить подобные адреса, необходимо консул настроить с параметром recursors:
"recursors": ["8.8.8.8"]
Итого
На мой взгляд, Consul на текущий момент это самая продвинутая и интерсная система, которая помогает уменьшить сложность деплоя, конфигурации и прочих инфраструктурных моментов.
В следующей статье приведу примеры Python кода и покажу, как использовать service discovery и kv store.
Вдохновение для статьи черпал отсюда:
Комментарии
Comments powered by Disqus