Перейти к главному содержимому

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. Сюда же относится автоматическая балансировка запросов на живые ноды. Жизненный цикл сервиса выглядит так:

  1. Приложение регистрируется в каталоге, сообщая своё имя и порт.
  2. С помощью health checks производится проверка, что приложение работоспособно.
  3. Если приложение остановилось или упало, консул перестаёт балансировать на него нагрузку. В этот момент нода помечается как проблемная. По истечении определённого таймаута регистрация приложения удаляется. Актуальную информацию о проблемных нодах и их статусе, можно посмотреть в веб-интерфейсе.

Получить адрес и порт нужного сервиса клиенты могут с помощью HTTP Api или DNS запросов (консул поднимает свой DNS сервер на порту 8600). Как использовать http api можно прочитать здесь, а про DNS здесь.

Централизованное управление конфигурацией

Благодаря своему KV-store, Консул может выступать в роли центрального хранилища конфигурации для приложений. Работать это может двумя способами:

  1. Если приложение конфигурируется через переменные окружения, то можно использовать утилиту envconsul, которая будет трансформировать ключи из KV хранилища в environment variables и запускать новый сервис. Это удобно тем, что при изменении конфигурации через consul ui, envconsul автоматически перезапустит нужный сервис.

  2. Приложение может само ходить в консул и брать нужные настройки оттуда. Это может быть удобно для изменения поведения приложения в рантайме, например, с помощью feature-flags.

Конечно, можно смешивать оба подхода для получения большего профита.

Балансировка нагрузки между сервисами

Консул автоматически балансирует нагрузку только на живые ноды. Здесь же затрону момент, когда необходим реверс-прокси.

  1. nginx. Для балансировки через nginx приходится прописывать апстримы в конфиг-файле. Чтобы не делать этого вручную можно использовать утилиту consul-template, которая по шаблону сгенерирует конфигурационный файл (автоматически при старте и изменении статуса нод) с нужными хостами и портами и перезагрузит nginx.

  2. Для максимально ленивых есть 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