Рубрика:
Разработка /
Веб-технологии
|
Facebook
Мой мир
Вконтакте
Одноклассники
Google+
|
АЛЕКСАНДР КАЛЕНДАРЕВ, OTG, руководитель группы (ТимЛид), akalend@mail.ru
Современная веб-архитектура От монолита к микросервисам
Микросервисы – это небольшие самодостаточные программы или сервисы, которые выполняют одну маленькую задачу. Они работают совместно с другими программами (сервисами)
Современные тенденции развития веб-архитектуры ведут к постоянному усложнению. При разработке, улучшении и дальнейшем развитии успешного веб-приложения наступает такой момент, что становится тяжело поддерживать существующий код, тяжело внедрять новые решения. И тут архитектор задумывается о разделении проекта на небольшие части. Это и есть первый шаг к микросервисам.
Стиль разработки микросервисов – это подход, при котором единое приложение строится, как набор небольших сервисов. При этом каждый из них работает в собственном окружении и общается с остальными. Практически это могут быть крон-задачи, небольшие сетевые демоны, HTTP-сервисы. Сами по себе эти сервисы могут быть написаны на разных языках и использовать разные технологии хранения данных.
Основные преимущества микросервисной архитектуры:
- автономные сервисы позволяют быстрее локализовать неисправность;
- скорость разработки маленького проекта, где минимальная связанность компонент выше;
- масштабирование проще;
- технологическая разнородность позволяет внедрять сервис с использованием тех технологий, которые наилучшим образом подходят для решения данной подзадачи;
- лучше устойчивость, как в маленьких проектах;
- простота развертывания;
- быстродействие, простой маленький проектик дает более быстрый отклик, чем монструозное приложение.
Принципы рефакторинга
Один из первых шагов – это уменьшение связанности, выделение и обособление общих частей. Когда я работал в проекте «Война танков», там у нас, кроме основного игрового сервера приложений, использовалась микросервисная архитектура, в которой были выделены специальные сервисы:
- сервис авторизации, он позволял авторизироваться в разных соцсетях;
- сервис начальных установок, используемый разными микросервисами на стадии запуска;
- сервис биллинга игровых валют;
- сервис сбора игровой статистики.
При таком подходе разработка новых игр позволяла нам сосредоточиться только на разработке и внедрении игровой логики в сервере приложений и использовать уже существующую инфраструктуру ранее внедренных проектов сминимальными издержками.
Еще один пример из практики. При эксплуатации одной службы знакомств мы заметили, что нагрузка на сообщения превышает в несколько раз нагрузки остальных служб. Сервер сообщений вынесли в отдельный микросервис и запустили на нескольких машинах. В общем итоге после некоторой оптимизации серверов у нас освободилось две машины.
Как это все происходит? Например, в текущем проекте мы разрабатываем проект сайта доставки еды. У нас админпанель реализовывалась на Laravel как эффективный фреймворк для разработки СRM и общей архитектуры с механизмами миграций БД. А API был реализован на Phalcon как наиболее производительный фреймворк. Это особенно видно, когда идет разработка под мобильные устройства.
В нашем проекте API был реализован единым для веб- и мобильной разработок. А вот сам фронтенд, веб-часть реализованы на Node.js. И так у нас появились три независимые части проекта, которые лежат в трех репозиториях иразрабатываются отдельно. Тут появляется задача – необходимо держать три раздельных, но в то же время практически одинаковых конфигурационных файла. А можно добавить еще один микросервис – раздачи конфигурационных данных.
Предыдущий проект тоже был связан с доставкой и отслеживанием курьеров. Какая-то часть одного проекта может быть использована для реализации второго. Повторное использование кода – это часто применяемая практика. Так вот, эту часть можно выделить как специальный микросервис. Например, микросервис баннеров акций, проводимых на сайте, и учета их эффективности, т.е. сколько покупок сделали по этому баннеру.
Разработка микросервисов – это подход, при котором единое приложение строится, как набор небольших сервисов |
Также в рамках проекта можно выделить специальный сервис по расчету цены доставки. Цена на доставку в конечный адрес может меняться от разных условий: день недели, время суток, наличие бонусной карты. Цена доставки зависит отзоны, которая определяется по полигонам, которые рисуются на карте контент-менеджером, а цену устанавливает экономический отдел в собственной системе CRM или даже в 1С, экспортирующей данные в микросервис.
Для лучшего сбыта товаров есть такая функция «с этим товаром чаще всего покупают...». Я просмотрел реализацию: в большинстве случаев сделана привязка конкретного товара к определенному списку товаров. Но было бы интересно анализировать каждую корзину и на основе статистики строить такие рекомендации. Также, если мы вручную «рекомендуем» тот или иной товар, то как часто люди «следуют» этой рекомендации?
Это очень интересная аналитическо-статистическая задача, и ее хорошо решать в рамках отдельного микросервиса. Такой рекомендательный сервис с разными стратегиями на основании учета статистики можно будет использовать впохожих проектах с возможностью экономии на внедрении.
Как должны быть реализованы микросервисы? Основной принцип построения микросервисной архиетктуры – это изолированность. Микросервис должен быть изолирован и самодостаточен. Он может быть реализован как сетевой демон или HTTP-сервис.
Он может быть даже реализован как небольшой внедренный в nginx Lua скрипт. Микросервис должен решать одну небольшую задачу. Насколько она должна быть небольшой – это уже решать вам. Например, для защиты API я в рамках nginx реализовал на Lua микросервис, который сравнивал токены и валидировал запросы.
С какой стороны подойти к рефакторингу монолита? Во-первых, нужно четко выделить границы в коде между модулями. Обычно это происходит по функциональному принципу.
Второе: надо иметь ясное понимание того, что необходимо вынести в отдельный микросервис. Необходимо продумать свою систему хранения данных для каждого микросервиса. И еще надо помнить основной принцип рефакторинга – эторазработка через тестирование: пишем тесты и еще раз тесты.
Коммуникация микросервисов
Разбиение монолитной системы на части предполагает, что эти самодостаточные части начнут обмениваться информацией. Для обмена микросервис может использовать как REST-Full API + JSON поверх HTTP-протокола, так и разные бинарные протоколы: BSON, msgpack, protobuf при сокетном обмене. Например, в одном из проектов, где я работал, все наши микросервисы общались по текстовому memcached-протоколу. Но, как показала впоследствии практика, он неполностью удовлетворял нашим потребностям, и приходилось его расширять.
Использование стандартных протоколов имеет свои плюсы: нет необходимости специально разрабатывать стыковочные (интерфейсные) части программ. Уже есть готовые клиенты под множество языков, реализующие данный протокол.
Один из используемых приемов построения архитектуры называется pipe-line-архитектура.
На рис. 1 изображен общий принцип pipe-line-архитектуры. Есть один сервис, который отправляет в «канал» сообщение для второго сервиса, а второй сервис отправляет в следующий «канал» сообщение для третьего сервиса. Третий сервис, в свою очередь, может отправить в канал сообщение следующему сервису. И таким образом строится обмен, который проходит через брокеры (серверы) сообщений. Такими брокерами могут выступать либо общие middleware, такие какredis, tarantool, MongoDB или даже PgQueue, либо специализированные: MemcacheQ, ZMQ, RabbitMQ, Kafka, Qpid, IronMQ, ActiveMQ, Beanstalkd, Gaerman и др. Каждый из них имеет свою нишу.
Рисунок 1. Принцип pipe-line-архитектуры
Передача данных через сообщения позволяет асинхронно взаимодействовать между элементами архитектуры, сохраняет слабую связанность между элементами архитектуры и дает возможность взаимодействовать с разными частями, реализованными на разных языках: PHP – Python – Java – Go – JS -Scala – Erlang...
Когда-то я работал в проекте Tradebox, который был аналогом Yandex-Market. Что у нас творится под капотом витрины: сервис должен загрузить YML-данные о товарах из нескольких тысяч магазинов. Проанализировать данные и разобрать их по каталогам. Привязать данные к основному каталогу, который отображается на веб-витрине. Загрузить отсутствующие картинки товаров. А не привязанные данные – отобразить контент-менеджеру для последующей «ручной» привязки к данной категории.
В данном проекте напрашивается как минимум пять микросервисов:
- загрузка контента;
- анализ контента;
- загрузка картинок;
- отображение веб-витрины;
- CMS-контент менеджера.
Архитектуру взаимодействия между первыми тремя микросервисами можно организовать через сервер очередей, например RabbitMQ.
Так как контента требуется загрузить много и процесс загрузки занимает достаточно времени, то данную задачу было бы логично распараллелить между несколькими микросервисами. Для этого нам лучше всего использовать паттерн «Подписка/Публикация» (см. рис. 2).
Рисунок 2. Паттерн «Подписка/Публикация»
Приложение «Публикатор» или «Продюсер» генерирует сообщения и отправляет их в канал. На этот канал «подписывается» несколько приложений «слушателей» или «подписчиков» (в разных интерпретациях этого паттерна термины трактуются по-разному).
При поступлении сообщения в брокер оно передается одному из активных подписчиков (это особенность RabbitMQ). Активный подписчик (микросервис) выполняет некоторые действия и далее отправляет результат в другой канал сообщений.
Какие проблемы могут возникнуть при распараллеливании процесса? Во-первых, это конкурентный доступ к ресурсам. Каждый из процессов требует обращения к хранилищу данных, к общим областям памяти. При запуске большого числа однотипных микросервисов потребуется их балансировка, необходим механизм равномерного распределения нагрузки заданий на микросервисы.
Виртуализация
В микросервисной архитектуре разработчику приходится использовать одновременно сразу несколько микросервисов. Осуществлять сборку и разворачивание на одной разработческой машине не всегда удобно, особенно когда таких микросервисов много. Для более быстрого разворачивания системы лучше использовать виртуализацию: виртуальные машины или контейнеры.
Один из недостатков использования виртуальных машин заключается в том, что запуск их большого количества может привести к перегрузке машины разработчика. Если в нашей архитектуре заложено так, что у нас на каждой отдельной виртуальной машине разворачивается по одному сервису, то может случиться так, что разработчик на своей локальной машине просто не сможет настроить инфраструктуру всей системы.
Docker представляет собой платформу, являющуюся надстройкой над облегченными контейнерами, и по сравнению с виртуальными машинами требует меньше системных ресурсов. Часто при развертывании используется собственный docker-репозиторий, в котором хранятся образы с уже готовыми микросервисами. Разработчику для настройки локальной инфраструктуры всего лишь требуется «поднять» несколько docker-образов с уже готовыми микросервисами.
Мониторинг
Если у нас микросервис запущен как отдельная служба, то необходимо отслеживать работоспособность этой службы. Брать ее отдельные параметры, например накапливать микросервисом статистику о количестве обработанных заданий впериод заданного времени или с начала запуска. Обязательно мониторить такой микросервис, как память на наличие утечек. Отвечает ли микросервис? Не завис ли он?
Если приходится мониторить одновременно несколько однотипно запущенных микросервисов на одной физической машине, то тут в метриках надо обязательно указывать, с какого сервиса (pid, id или уникальный номер запущенного микросервиса) снимались метрики. В этом случае мы можем выяснить общую картину по равномерности нагрузки и работоспособности каждого отдельного микросервиса.
Если микросервис запущен как отдельное веб-приложение, то необходимо отслеживать наличие 500 и 400 ошибок.
Если в архитектуре используются очереди, то обязательно необходимо мониторить количество элементов в каждой очереди. Идеально если длина очереди равна нулю. Среднее значение длины очереди может быть и больше нуля, ноприроста быть не должно. Если очередь явно растет, то где-то что-то не обрабатывается. По мере роста очереди мы можем понять, что обработчик (получатель) сообщений не успевает с их обработкой, и мы можем добавить (запустить) еще один экземпляр микросервиса.
В 2014 году Баттери Вентура представил основные правила мониторинга микросервисов:
- Работайте больше над кодом, который анализирует значение метрик, чем над кодом, который их собирает, переносит и показывает.
- Снижайте задержки ключевых бизнес-метрик не более чем продолжительность концентрации внимания человека (до ~ 10 с).
- Система измерения должна иметь достаточную точность. Осуществляйте сбор гистограмм времени отклика.
- Системы мониторинга должны быть более доступными и масштабируемым, чем системы, которые мониторятся.
- Осуществляйте мониторинг распределенных, облачных и контейнерных микросервисов.
- Установите метрики для моделей, чтоб понимать «физику отношений».
Есть «промышленные» решения, которые осуществляют мониторинг запущенных микросервисов в контейнерах (vagrant, docker), анализируют длину очередей, при необходимости сигнализируют потребность запуска «новых» контейнеров: Loggly, Dynatrace, Prometheus.
- Сэм Ньюман. Создание микросервисов. – O'Reilly, 2016.
- Грогор Хоп, Бобби Вульф. Шаблоны интеграции корпоративных приложений. – М.: Вильямс, 2007.
Facebook
Мой мир
Вконтакте
Одноклассники
Google+
|