Что здесь интересного:

image

Обзорная статья о Consul (http://consul.io) — системе для поддержания обнаружения сервисов и распределенного хранилища ключ-значение. Кроме самого Consul, рассмотрим Consul-Template — средство для управления конфигурациями сервисов автоматически отражающее изменения в топологии. Статья будет интересна DevOps инженерам, системным архитекторам, тим-лидам проектов и прочим интересующимся микросервисными архитектурами.

Естественно я не могу осветить все аспекты функционирования и использования Consul но в статье будет описано достаточно, чтобы пытливый читатель заинтересовался и продолжил изучение глубже.

Consul: «что за птица — с чем едят?»

Лирическое отступление, но по теме.
В текущем мире огромных объемов данных, где распределенные системы их обработки становятся не чем-то из мира недостижимой фантастики но обыденными вещами, вопросы их правильного проектирования и реализации становятся очень важным моментом в последующем развитии этих систем. Каждый, кто хотя бы раз принимал участие в разработке архитектур автоматически масштабируемых, распределенных систем, знает что этот процесс очень трудоемкий и требующий достаточно серьезного стека знаний систем из которых можно строить подобные архитектурные решения. С учетом бурного развития облачных вычислений и появления IaaS платформ — разворачивание масштабируемых систем стало достаточно простым делом. Однако взаимодействие компонентов таких систем (интеграция новых компонентов, удаление неиспользуемых частей и т.д.) всегда вызывает головную боль у архитекторов, devops инженеров и программистов. Для этих целей можно придумывать свой велосипед (шаблоны конфигурационных файлов, поддержка саморегистрации со стороны приложения и т.д.), можно использовать локальные или распределенные системы хранения данных «ключ-значение» (redis, zookeeper, etcd и др.) а можно использовать системы обнаружения сервисов (Service Discovery).

Часто термин Service Discovery (в дальнейшем я буду использовать сокращение — SD) относится к системам сетевого обнаружения (протокол SDP, к примеру) но в последнее время SD используется и в программной части архитектур для взаимного обнаружения связанных компонентов систем. Особенно это касается микросервисного подхода к разработке программных комплексов. MSA (Micro Services Architecture), одними из первопроходцев и популяризаторов которой является Netflix, все чаще становится стандартом для разработки распределенных, авто-масштабируемых, высоко нагруженных систем. И Consul уже много где используется для обеспечения SD в подобного рода системах. К примеру Cisco использует его в своем движке для MSA — Cisco MI.

Собственно, Consul и есть удачное объединение K/V хранилища и SD функционала. Ну а теперь подробнее.

Consul: Чем он лучше?

Достаточно резонный вопрос «Зачем нам Consul, если у нас есть Zookeeper и он прекрасно справляется с задачей SD?». Ответ на поверхности — Zookeeper, и подобные системы (etcd, doozerd, redis, etc) не предоставляют функционала SD — их задача всего-лишь хранить данные в том или ином формате и гарантировать их доступность и консистентность в каждый отдельный момент времени (при условии правильной настройки и использования, конечно). Естественно такой модели будет вполне достаточно для обеспечения SD, но вот удобство использования (настройки, обслуживания, и т.д.) частенько оставляет желать лучшего.

К примеру, Zookeeper: это постоянная возня с его кластером, — начиная с первичной настройки (автоматизированная установка zk кластера средствами Ansible или SaltStack может доставить немало хлопот даже продвинутому специалисту), заканчивая передачами софту, использующему Zookeeper, ссылок на кластер вида zk://10.10.1.2:2181,10.10.1.3:2181,10.10.1.5:2181/app (необходимо предварительно знать где расположен кластер, все его ноды). Мало того, — если кластер Zookeeper по какой-то причине «переедет» на другие адреса (очень актуально в облачных средах, MSA архитектурах), придется перезапускать все использующие этот кластер приложения и сервисы.
С Consul все проще: ребята из HashiCorp сделали «все для людей». Consul распространяется как 1 бинарный файл (нет надобности следить за зависимостями, использовать пакетные менеджеры) и любой софт использующий Consul всегда делает запросы к нему на localhost (нет надобности хранить ссылку на кластер или master ноду сервиса), — Consul все берет на себя. Использование Gossip в качестве протокола обмена данными делает Consul быстрым, отказоустойчивым и не требующим выделенного мастера для нормального функционирования. На самом деле мастер как таковой формально имеется (даже кворум мастеров) но это необходимо по большей части для того, чтобы пережить полную остановку всех нод кластера (мастера обеспечивают периодическое сохранение оперативных данных на диск тем самым гарантируя персистентность данных). В итоге, для приложения (микросервиса) использующего Consul вся работа с SD сводится к общению с localhost:8500 — куда бы не переехало приложение — там всегда будет агент Consul. Мало того, для работы с Consul не нужно иметь каких-либо клиентских библиотек (как в случае с Zookeeper) — для этого используется простой и понятный HTTP REST API (простые данные, не более 20 разных API функций), либо DNS сервисы с SRV записями (да, — одна из функций Consul — предоставление DNS интерфейса к зарегистрированным сервисам).
Более подробно можно почитать тут.

Consul: Как поставить, и начать работу?

Сразу скажу, что останавливаться подробно на установке и настройке мы не будем — для читающих статью, думаю, это будет достаточно простым упражнением. Лишь одна проблема достойная внимания, — не прозрачность в поиске документации по установке на сайте, потому вот ссылки: начальная установка (как домашнее задание — разработка start/stop скриптов для своего любимого init.d/upstart/systemd — ненужное — вычеркнуть), запуск агентов и инициализация кластера.

Пара замечаний по поводу выбора топологии кластера. Не лишним будет отметить, что Consul не имеет обособленного мастера, который единолично принимал и распространял бы конфигурации сервисов и данные между нодами, — абсолютно любой агент может быть использован для регистрации сервисов и данных. Вообще-то говоря, мастер (точнее кворум мастов) как таковой имеется, и его основная роль — обеспечение персистентности данных при рестартах кластера.

Consul: Регистрируем сервис, используем запросы

Итак, имея готовый кластер (или одну ноду для тестов) начнем регистрировать сервисы. Для начала сгенерируем гипотетический сценарий на базе которого будем дальше разбираться с работой Consul: предположим у нас есть классическое web приложение состоящее из нескольких frontend сервисов, нескольких backend сервисов и хранилища данных — пусть будет mongodb. Оговорим сразу же, что инфраструктура тестовая и вопросы наподобие: почему MongoDB не кластеризован?, почему HAProxy, а не Nginx? и т.д. оставляю пытливому читателю в качестве домашнего задания.
При работе с Consul мы будем различать 2 вида сервисов — активные (использующие http rest api для собственной регистрации и внедрения проверок доступности) и пассивные (требующие предварительно приготовленных конфигурационных файлов для Consul). К первым будем относить сервисы разрабатываемые локально (продукт компании и его компоненты), ко вторым: сторонние приложения (необязательно поддерживающие работу с Consul, или не поддерживающих ее вообще, — к примеру MongoDB).

Итак, введем регистрацию для MongoDB сервиса — создадим файл /etc/consul.d/mongodb.json:

{
  "service": {
    "name": "mongo-db",
    "tags": ["mongo"],
    "address": "123.23.34.56",
    "port": 27017,
    "checks": [
      {
        "name": "Checking MongoDB"
        "script": "/usr/bin/check_mongo.py --host 123.23.34.56 --port 27017",
        "interval": "5s"
      }
    ]
  }
}

Самое важное тут:
1. address/port — собственно именно эти данные будут получать клиенты Consul в ответ на запрос информации о сервисе «mongo-db». Публикуемый адрес должен быть доступен.
2. Секция «checks» — список проверок позволяющих идентифицировать жив ли сервис. Это может быть любой скрипт (возвращающий 0 в случае нормального функционирования сервиса; 1 в случае warning статуса сервиса и любое другое значение в случае недоступности сервиса), http проверка (запрашивается некий URL и на основании ответа генерируется состояние сервиса — HTTP/2XX — сервис жив, HTTP/4XX, HTTP/5XX — сервис недоступен).

Подробнее на сайте: описание сервиса, описание проверок.

Последующий рестарт агента (с указанием /etc/consul.d/ как каталога с конфигурациями) примет этот файл и зарегистрирует MongoDB как сервис доступный для SD. Скрипт указанный в секции checks делает подключение к MongoDB на указанном хосте (тестируя доступность сервиса) и, к примеру, делает запрос к какой-то коллекции для проверки доступности данных.
В последствии проверить регистрацию можно при помощи curl:

~/WORK/consul-tests #curl -XGET http://localhost:8500/v1/catalog/service/mongo-db
[{"Node":"mpb.local","Address":"192.168.59.3","ServiceID":"mongo-db","ServiceName":"mongo-db","ServiceTags":["mongo"],"ServiceAddress":"123.23.34.56","ServicePort":27017}]

Или с помощью встроенного в Consul DNS сервера:

~/WORK/consul-tests #dig @127.0.0.1 -p 8600 mongo-db.service.consul SRV

; <<>> DiG 9.8.3-P1 <<>> @127.0.0.1 -p 8600 mongo-db.service.consul SRV
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 50711
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;mongo-db.service.consul.	IN	SRV

;; ANSWER SECTION:
mongo-db.service.consul. 0	IN	SRV	1 1 27017 mbp.local.node.dc1.consul.

;; ADDITIONAL SECTION:
NEST.local.node.dc1.consul. 0	IN	A	123.23.34.56

;; Query time: 1 msec
;; SERVER: 127.0.0.1#8600(127.0.0.1)
;; WHEN: Thu Sep 17 17:47:22 2015
;; MSG SIZE  rcvd: 152

Использование того или иного способа получения данных из Consul зависит от архитектуры запрашивающего компонента (для скриптов удобнее использовать DNS интерфейс, для компонентов написанных на ЯП высокого уровня — REST запросы или специализированные библиотеки).

Все сервисы, которые могут поддерживать саморегистрацию должны использовать библиотеки для необходимых ЯП: python, java, go, ruby, php. Необходимо не забывать помимо, собственно регистрации сервисов, грамотно разрабатывать скрипты проверки доступности того или иного сервиса чтобы не получить систему с зарегистрированными но не работающими сервисами.

Consul: Прощайте конфигурационные файлы.

Собственно добрались до самой сути, — дочитавшим посвящается… Итак в какой-то определенный момент времени мы получили среду в которой зарегистрированы сервисы (mongodb, backend, — к примеру) какую же выгоду можно получить?
В традиционных распределенных системах (без внедренного SD) используются в основном такая техника для добавления нового компонента в систему (скажем при росте нагрузки необходимо создать еще один backend):
1. Создается инстанс backend сервиса (зачастую при помощи систем оркестровки типа SaltStack/Puppet/Ansible/Hand-Made scripts/etc)
2. Система оркестровки по шаблонам генерирует новые конфигурационные файлы для сервисов использующих backend (load balancers, frontends, etc)
3. Та же система оркестровки генерирует конфиг файл для этого нового backend сервиса, указывая в нем контактную информацию о mongodb и прочих зависимых компонентах
4. Все зависимые сервисы перечитывают конфигурацию (или рестартуют) пересоздавая соединения между собой
5. Система дожидается конвергенции и переходит в рабочее состояние.

Подобный подход очень затратен — необходимо сделать генерации конфиг файлов, их распространение, перезапуски сервисов и т.д. Ко всему — в процесс вовлечена система оркестровки (сторонний по отношению к рабочей системе компонент) за доступностью которой тоже нужно следить.

SD позволяет существенно упростить этот процесс (как именно, пытливый читатель уже думаю догадался), но требует изменения поведения самих сервисов входящих в систему. И это не только поддержка SD (регистрации сервиса и обнаружения сервисов), но и Fail Tolerance (способность сервиса безболезненно переживать изменения в топологии подчиненных сервисов), активное использование KV хранилищ для обмена конфигурационной информацией, и т.д.
Единственный внешний компонент, который придется использовать в таких конфигурациях — Consul-Template — средство для подключения к Consul разнообразных, не поддерживающих SD, систем, к примеру: HAProxy. Задача этого программного средства отслеживать регистрации/дерегистрации сервисов и изменять конфигурации подчиненных сервисов, т.е. при регистрации нового backend автоматически будет перестроен конфиг HAProxy для включения этого нового инстанса в процесс балансировки нагрузки. Подробнее об этом можно почитать тут.
Собственно применение SD на базе Cunsul, Consul-Template, Consul-KV в принципе может помочь полностью избавится от каких-либо конфигурационных файлов и оставить все на откуп Consul.

Как заключение.

В целом, из-за того, что Consul находится в фазе активной разработки возможны некоторые проблемы (из замеченного мной — проблемы с развалом кластера при рестарте всех нод с Consul), но базовый функционал SD работает нормально и каких-либо нареканий незамечено. Напомню еще о поддержке Consul'ом множества дата-центров для обеспечения распределенности.

Комментарии (13)


  1. baldr
    22.09.2015 12:43
    +1

    Начал читать и подумал — а идея правильная, SD сейчас актуален в больших сервисах, интересно как они это предлагают…

    Но по ходу чтения статьи совершенно не понял в чем преимущество перед системами оркестрации. Нам нужно поменять некоторые параметры в конфигах для 20 серверов, скажем. Причем, не все сразу, а по-очереди, сначала на базах, а потом на веб-серверах. Как нам тут поможет Consul и почему в нем это будет проще?

    Представим, что у нас есть сервис с 2000 серверов и уже настроен, скажем, Zabbix с локальными агентами, которые проверяют состояник сервисов. Нам теперь еще надо для каждого сервиса написать конфиг для Consul, который будет делать то же самое?

    На мой взгляд такие системы были бы удобнее не как отдельный сервис, а как библиотека, встраиваемая непосредственно в код — особенно для самописных сервисов.


    1. eugenechepurniy
      22.09.2015 13:07

      Ну, во первых Consul — это не замена для систем оркестровки — это разные вещи. Определенно одна из причин Вашего недовольства очень проста: это попытка натянуть на текущую спроектированную и отлаженную систему Consul и попытаться его как-то использовать. Да — это ни к чему хорошему не приведет, скорее даже наоборот — добавит массу неудобств и «костылей» чтобы все это запустить.
      Внедрение Consul и SD больше подходит для систем которые находятся в состоянии начального проектирования, либо для таких, архитектура которых себя исчерпала и требуется рефакторинг (читай перепроектировать систему и переделать ее компоненты).

      В примере с Zabbix-ом — тоже разночтение: Consul использует health-check проверки для того, чтобы дерегистрировать сервис, который более не может выполнять свои функции и не может быть больше использован другими компонентами системы. Consul ни в коем случае не заменит мониторинговую систему.


      1. baldr
        22.09.2015 13:56

        Consul: Прощайте конфигурационные файлы.

        SD позволяет существенно упростить этот процесс (как именно, пытливый читатель уже думаю догадался)

        Вот на этом месте и возникли вопросы. Не могли бы вы подробнее рассказать, чтобы не было недопониманий?
        Если это разные вещи, то зачем вы их сравнивали?
        Если вы имели в виду отказ от конфигов с помощью авторегистрации в коде — то да, в своем коде мы можем это сделать и это было бы очень удобно. Но что там про mongodb и кластер?


        1. eugenechepurniy
          22.09.2015 14:20
          +2

          Не хотелось бы превращать обзорную статью в полноценный гайд по использованию SD. Но можно попробовать кратенько. Итак методология простенького сценария такова:
          1. запускаем MongoDB и регистрируем ее в Consul
          2. запускаем микросервис(ы) который использует MongoDB как хранилище. Сервис вместо того, чтобы лезть в свой конфиг-файл (где указано системой оркестровки адрес MongoDB сервера и его порт), делает запрос в Consul (по ссылке localhost:8500/v1/catalog/service/mongo-db) и получает данные о том, куда ему подключаться.
          3. проходит некоторое время и MongoDB сервер меняет хост (достаточно частый случай для облачных сред, Mesos кластеров и прочих IaaS сервисов; и удержимся от описания того, как данные будут мигрировать)
          4. В обычных случаях (без SD), начинаем: zabbix рапортует о том, что монга умерла, запускаем оркестратор — генерим новую монгу, генерим куче сервисов новый конфиг файл с атрибутами коннекта к новой монге, перезапускаем их. В случае с SD, приложение получает connection drop с сервером MongoDB и переходит в состояние некое состояние standby во время которого периодически опрашивает Consul на предмет регистрации нового инстанса MongoDB. Получив данные о регистрации — переподключается.
          Очевидная выгода в том, что не используются сторонние по отношению к системе компоненты (системы мониторинга и оркестровки, — но я не призываю не использовать их вообще), сервисы не рестартуют продолжая выполнять какие-то запросы не зависящие от наличия подключения к MongoDB, и таки — отсутствие конфигурационных файлов (не в общем как таковых, но в данном конкретном случае можно без них).

          В любом случае — интеграция Consul это не просто «поставил-настроил-работает», — это серьезный архитектурный шаг и не факт, что он подойдет в любом случае.


          1. Suvitruf
            22.09.2015 16:11

            localhost:8500/v1/catalog/service/mongo-db

            Этот запрос же только сервис вернёт, без состояния. Я бы порекомендовал отправлять запрос сюда: localhost:8500/v1/health/service/mongo-db?passing
            Вернёт список всех инстансов mongo-db, которые прошли хелс чек.


            1. eugenechepurniy
              22.09.2015 16:29

              Отличное замечание. Можно и так, однако мне кажется, что предпочтительнее принудительно дерегистрировать сервис не прошедший health check, во избежание накопления мусора в Consul.


              1. Suvitruf
                22.09.2015 16:40

                Зависит от ситуации. У нас часть сервисов сами о своём состоянии сообщают консулу, используя /v1/agent/check/fail/, /v1/agent/check/warn/ и /v1/agent/check/pass/. Когда сервис слишком нагружен, он меняет свой стейт на fail или warn, тогда к нему временно не будут приходить новые запросы. Позже он опять обновит стейт на pass.


          1. icCE
            23.09.2015 09:19

            >Не хотелось бы превращать обзорную статью в полноценный гайд по использованию SD. Но можно попробовать кратенько. Итак методология простенького сценария такова:

            Я бы хотел лично увидеть и гайд нормальный и примеры под которые консул будет хорошо использовать. Да и примеры где его не надо использовать.


            1. eugenechepurniy
              23.09.2015 10:02
              +2

              Дело в том, что Вы не найдете гайдов по Consul — весь гайд это описание API и пара несложных примеров его использования. Да и не может быть гайдов в принципе (равно как и условий в которых можно использовать только Consul) и причина этого очень проста: Consul это не самостоятельный программный продукт, а один из строительных кирпичиков MSA (при чем не обязательно незаменимый). Consul достаточно трудно натянуть на уже работающую систему без структурных изменений ее архитектуры, мало того — многим системам совершенно и не нужны микросервисы, SD и все, что с этим связано. Но, если Вы системный архитектор и в данный момент проектируете систему которая должна легко масштабироваться, быстро разрабатываться и меняться под новые потребности, — без подходов заложенных в MSA Вам вряд ли обойтись. И вот тут уже приходит на помощь Consul — как часть микросервисной архитектуры отвечающая за SD компонентов.
              Как таковым гайдом/примером использования может служить полное описание распределенной системы использующей Consul, но подобное описание вряд ли разрешат предоставить владельцы таких систем.


  1. Suvitruf
    22.09.2015 13:27
    +1

    Используем Consul для сервис дискавери на своих серверах. Пока никаких проблем не было. Три мастера + клиент на каждой машине. Хелс чеки можно как и со стороны консула сделать, так и из самих приложений. Если делать на стороне самого консула, то можно кастомные скрипты использовать. В придачу можно настроить DNS Interface. В общем, очень полезная вещь.


  1. Valistar
    23.09.2015 13:09

    Объясните пожалуйста, не понимаю. Ну вот мы перестали писать в конфигах address:port (а еще может нужно знать какая db, какая collection) MongoDB.

    Теперь пишем в конфиг discoveryUrl = http://localhost:8500/v1/catalog/service/mongo-db

    получается поменяли шило на мыло??

    а если нужно будет не один mongo-db а несколько (тестовый, промышленный)

    а если еще нужно будет чтобы какой mongo-db выбирать зависело от какого нибудь значения??? Saas Multi-tenancy например…


    1. eugenechepurniy
      23.09.2015 13:25

      Теперь пишем в конфиг discoveryUrl = localhost:8500/v1/catalog/service/mongo-db

      Фишка в том, что discoveryUrl фиксирован (он на всегда localhost и формат запроса стабилизирован) и описывать в конфиг-файле сервиса его не имеет смысла. Единственное что нужно — соглашение об именовании сервисов.
      а если нужно будет не один mongo-db а несколько (тестовый, промышленный)

      И тут не проблема — просто нужно зарегистрировать разные версии с разными именами или использовать механизм тегирования при объявлении сервиса.
      По поводу того какая база или коллекция должна быть использована — Consul KV может быть использован для прозрачной передачи каких-либо настроек. Подробнее в документации.


      1. Suvitruf
        24.09.2015 12:53

        Да зачем разные. Там при регистрации сервиса можно же указывать массив тегов. Так что, можно иметь одно имя сервиса, а фильтровать нужное по тегам потом.