Монолитная vs Микросервисная архитектура


Оглавление (нажмите, чтобы открыть):

Микросервисы против монолитной архитектуры

Я немного читал о микросервисах, и я немного заинтригован. Кажется, это интересная концепция. Но мне интересно, какие преимущества и недостатки используют микросервисы над монолитной архитектурой и наоборот.

Когда микросервисы подходят лучше, и где лучше идти с монолитной архитектурой.

Пока я относительно новичок в мире микросервисов, я постараюсь ответить на ваш вопрос как можно полнее.

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

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

Кроме того, развертывание приложения проще, поскольку вы самостоятельно создаете независимые микросервисы и развертываете их на отдельных серверах. Это означает, что вы можете создавать и развертывать службы, когда захотите, без необходимости перестраивать остальную часть вашего приложения.

Поскольку разные службы небольшие и разворачиваются отдельно, очевидно, что они легче масштабируются, с тем преимуществом, что вы можете масштабировать определенные сервисы своего приложения (с монолитным вы масштабируете полную «вещь», даже если это только определенная часть приложения, которая получает чрезмерную нагрузку).

Однако для приложений, которые не предназначены для того, чтобы стать слишком большими для управления в будущем. Лучше сохранить его в монолитной архитектуре. Поскольку архитектура микросервисов имеет некоторые серьезные трудности. Я заявил, что проще развернуть микросервисы, но это справедливо только по сравнению с большими монолитами. Используя микросервисы, у вас есть дополнительная сложность распространения сервисов на разных серверах в разных местах, и вам нужно найти способ обойти все это. Создание микросервисов поможет вам в долгосрочной перспективе, если ваше приложение станет большим, но для небольших приложений просто останется монолитным.

Это очень важный вопрос, потому что некоторые люди заманиваются от всех шумов вокруг микросервисов, и есть компромиссы для рассмотрения. Итак, каковы плюсы и минусы микросервисов (по сравнению с монолитной моделью)?

  • Развертывание: более гибкость для развертывания новых версий службы из-за более коротких циклов сборки + тестирования + развертывания. Кроме того, гибкость в использовании настроек безопасности, репликации, персистентности и мониторинга для конкретной службы.
  • Надежность: неисправность микросервиса влияет на эту микросервисную систему самостоятельно и ее потребителей, тогда как в монолитной модели служебная ошибка может разрушить весь монолит.
  • Доступность: развертывание новой версии микросервиса требует небольшого времени простоя, тогда как развертывание новой версии службы в монолите требует типично более медленного перезапуска всего монолита.
  • Масштабируемость: каждый микросервис можно масштабировать независимо с помощью пулов, кластеров, сеток. Характеристики развертывания делают микросервисы отличным сочетанием эластичности облака.
  • Модифицируемость: больше гибкости для использования новых фреймворков, библиотек, источников данных и других ресурсов. Кроме того, микросервисы слабо связаны, модульные компоненты доступны только через их контракты и, следовательно, менее склонны превращаться в большой шар грязи. Динамическое обнаружение и привязка через реестр (например, Apache ZooKeeper, Netflix Eureka) иногда используется для прозрачности местоположения.
  • Управление: усилия по разработке приложений распределяются между группами, которые меньше и работают более независимо.
  • Автономность дизайна: команда имеет право использовать различные технологии, рамки и шаблоны для проектирования и реализации каждого микросервиса и может самостоятельно изменять и переустанавливать каждый микросервис.
  • Развертывание: развертывание становится более сложным со многими заданиями, сценариями, областями передачи и конфигурационными файлами для развертывания.
  • Производительность: услуги, скорее всего, нуждаются в общении по сети, в то время как услуги в монолите могут воспользоваться локальными вызовами. Кроме того, если микросервис использует динамическое обнаружение, поиск в системном реестре является служебной нагрузкой.
  • Доступность: если вы используете реестр для динамического обнаружения, недоступность реестра может поставить под угрозу взаимодействие с потребителем.
  • Модифицируемость. Изменения в контракте, скорее всего, будут влиять на потребителей, развернутых в других местах, тогда как в монолитной модели потребители с большей вероятностью будут находиться в монолите и будут развернуты в блокировке с помощью службы. Кроме того, механизмы повышения автономности, такие как возможная согласованность и асинхронные вызовы, усложняют работу с микросервисами.
  • Testability: автоматические тесты сложнее настраивать и запускать, потому что они могут охватывать различные микросервисы в разных средах выполнения.
  • Управление: действие приложения увеличивается, потому что для наблюдения требуется больше компонентов времени выполнения, файлов журналов и взаимодействия «точка-точка».
  • Использование памяти: несколько классов и библиотек часто реплицируются в каждом наборе микросервисов, а общий объем памяти увеличивается.
  • Автономность выполнения: в монолите общая бизнес-логика совмещается. С микросервисами логика распространяется по микросервисам. Таким образом, при прочих равных условиях более вероятно, что микросервис будет взаимодействовать с другими микросервисами по сети — это взаимодействие уменьшает автономию. Если взаимодействие между микросервисами связано с изменением данных, потребность в транзакционной границе еще больше усугубляет автономию. Хорошей новостью является то, что во избежание проблем автономии во время выполнения мы можем использовать такие методы, как возможная согласованность, управляемая событиями архитектура, CQRS, кеш (репликация данных) и выравнивание микросервисов с ограниченным контекстом DDD. Эти методы не присущи микросервисам, но были предложены практически каждым автором, которого я читал.

Как только мы поймем эти компромиссы, еще одна вещь, которую нам нужно знать, чтобы ответить на другой вопрос: что лучше, микросервисы или монолит? Нам нужно знать нефункциональные требования (требования к атрибутам качества) приложения. Как только вы поймете, насколько важна производительность и масштабируемость, например, вы можете взвесить компромиссы и принять обоснованное дизайнерское решение.

От монолита к микросервисам

Цель статьи — в общих чертах обрисовать поэтапный процесс миграции от монолитной легаси системы к микросервисной архитектуре.

Что такое легаси-монолит?

  • Система, которой десятки лет; технологии и языки безнадежно устарели
  • Система, использующая библиотеки и фреймворки, которые даже вендор уже перестал или вот-вот перестанет поддерживать
  • Система, разработанная с использованием устаревших на текущий момент принципов построения архитектуры и дизайна
  • Система, функционирующая в окружении, в котором стоимость и сложность поддержки и развития неуклонно растет

Когда стоит задуматься о модернизации?

Отвлекитесь от текучки, мириад багов и бессонных релизных ночей и посмотрите на свои системы со стороны:

  1. В системе присутствуют ошибки, которые вы не можете исправить и их количество растет
  2. Устаревшая система — основной блокер; нет возможности развивать важную функциональность или выполнить требования производительности
  3. Сложно найти людей на поддержку системы; рынок людей, знающих технологию стремительно сокращается; новые люди хотят работать только с современными технологиями
  4. Высокая стоимость поддержки (и дешевле будет провести модернизацию, хотя ROI и не будет мгновенным)
  5. Никто не знает как система в действительности работает (разработчики давно уволились; документация ужасна; по сути система для вас — черный ящик)

Если для системы справедливы пункты 1-3 — срочно модернизировать, 4-5 — еще какое-то время проживет, но уже пора строить стратегию модернизации/перехода.

Суть подхода

Для крупных легаси систем наиболее безболезненным является постепенный переход от монолита к микросервисной по следующим причинам:

  • В компании может не быть экспертизы в разработке и управлении микросервисами. Постепенный переход позволит накопить такую экспертизу в контексте конкретной организации
  • Архитектура развивается эволюционно, держать под контролем важнейшие атрибуты качества при небольших инкрементальных изменениях проще
  • Переход на микросервисную архитектуру может потребовать изменения организацонной структуры компании в соответствии с обратным маневром Конвея, что может привести к увеличению штата, но как минимум некоторое время займет формирование новых процессов и правил взаимодействия
  • Микросервисная архитектура базируется иных принципах разработки и дизайна, чем разработка монолита и на адаптацию потребуется время
  • В микросервисной архитектуре потребуется изучение новых технологий и инструментов

Объект исследования

Рассмотрим самый тяжелый вариант, в котором сильные и запутанные связи распространяются и на FrontEnd и на BackEnd и на базу данных.

Новому — новое

Первое, что стоит сделать — перестать кормить монстра начать разрабатывать новую функциональность вне легаси системы. Для этого ставим между клиентом и нами прокси (например на API Gateway) и все обращения, связанные с новой функциональностью направляем на новый сервис (подробнее в статье о проксировании запросов). Так как в легаси системах редко кто задумывается о чистоте предметной области, а для реализации новой функциональности может понадобиться часть логики из легаси системы (которую можно запросить через обращение по API), следует на стороне нового сервиса ввести Anti Corruption Layer — он возьмет объекты старой предметной области легаси системы и переведет в новую, спроектированную по правилам предметно-ориентированного проектирования, сохранив тем самым новую модель чистой. Одновременно с вводом Anti Corruption Layer фиксируется технический долг об его вычленении из сервиса в будущем, когда необходимость отпадёт.

Раскол

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

Таким образом, параллельно с разработкой сервисов под новую функциональность будет полезным вернуть контроль над легаси системой и самое простое, что мы можем для этого сделать, — это отделить фронт от бизнес-логики и бизнес-логику от базы. Этот процесс — постепенный и отделение следует проводить в рамках текущей работы, то есть: если изменяется логика расчета скидок и их отображение, то именно в рамках этой области проводится отделение.

Можно запланировать разделение не затрагиваемых текущей разработкой областей в рамках отдельных технических задач. В таком случае важно, чтобы эти активности были видимы и понятны всем участникам процесса и должна учитываться при планировании предстоящей работы.

Разделение дает следующие преимущества:

  • Возможность независимого изменения фронта, бэка и базы позволяет вносить правки чаще
  • Если раньше было непонятно, с какой стороны подступиться с автотестами, то теперь открываются первые двери интерфейсы и возможность проведения тестирования от API и в изоляции от базы данных
  • Если на стороне фронта реализуется бизнес-логика, а бэк отвечает за представление — это становится очевидным; при некоторых подходах это оправдано, если же это приводит к сложностям — самое время провести рефакторинг и перенести код туда, где ему положено быть.

Огранка

Следуя принципу единственной ответственности применительно к пакетам/модулям и постепенно перенося функциональность, относящуюся к определенному контексту (BoundedContext) в рамки такого пакета мы неминуемо повышаем модульность и гибкость системы в целом. Такие пакеты становятся прекрасными кандидатами на роль микросервиса в будущем, но не стоит торопиться: до тех пор, пока углубляется понимание о предметной области, сущности могут мигрировать из одного контекста в другой и это проще проводить в рамках единой кодовой базы, чем между различными микросервисами в разных репозиториях.

На этом этапе у пакетов все еще может быть единый внешний API и единый слой доступа к данным, однако уже стоит озаботиться рефакторингом — пусть пакет и один, но постепенно необходимо идти к тому, чтобы отдельные пакеты не использовали один и тот же метод, а тем более класс, для доступа к требуемым данным.

Если отчетливо видно, что двум пакетам требуются данные из одного Dao-интерфейса, то возможны следующие ситуации:

  • Логика неверно распределена между контекстами
  • В результатах запроса смешаны данные, требуемые различными контекстами для разных целей
  • Это справочные данные
  • Существует более высокоуровневый контекст, который еще не идентифицирован и которому требуются данные из двух низкоуровневых

Теперь контекст включает в себя и логику доступа к данным и логику отображения данных и свои собственный API для предоставления данных и четко определенный интерфейс для взаимодействия с другими модулями системы. Последнее — важно. Не должно быть зависимостей между пакетами на уроне реализации, только через публичный интерфейсы, за которыми скрывается вся реализация пакета.

На уровне пакетов это выглядит следующим образом:

Покидая родную обитель

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

Нужно четко понимать, с какой целью и в каком порядке стоит выносить сервисы за пределы теперь уже хорошо организованного, модульного, монолита.

  • Повышенные требования к производительности и масштабируемости
  • Повышенные требования к скорости внесения изменений
  • Необходимость перехода на новую технологию
  • Потребность в независимом обновлении функциональности
  • Повышенные требования к устойчивости работы

Что дальше?

Статья написана на основе собственного опыта, книг, статей, опыта сообщества. В ней не так много технических деталей, не рассмотрены вопросы декомпозиции баз данных, подходы к интеграции, тестированию, развертыванию, безопасности, мониторингу, шаблоны микросервисов, подходы к моделированию микросервисов.

Обо всем этом в следующих статьях.

Что почитать?

Перевод статьи Мартина Фаулера «Микросервисы» (оригинал)

DevOps RU

Микросервисы — за и против

Одни команды разработчиков находят в микросервисной архитектуре преимущества перед монолитной. Другие же считают микросервисы лишней нагрузкой, снижающей производительность. Как и каждый архитектурный стиль, микросервисы несут в себе и преимущества, и недостатки. В этой статье мы расскажем в каких конкретных случаях лучше применять микросервисную архитектуру, чтобы выбор оказался разумным.

Микросервисы несут в себе преимущества. . но включают и недостатки
Жесткие границы модулей: Микросервисы – четкая модульная структура, что крайне удобно для больших команд. Распределенность: Распределенные системы сложнее программировать, так как удаленные вызовы работают медленно и невозможно исключить риск сбоя.
Независимое развертывание: Микросервисы проще в развертывании, и поскольку они автономны, меньше шансов вызвать сбои системы, когда они работают некорректно. Согласованность в конечном счете: Для распределенной системы сложно поддерживать строгую согласованность. Поэтому каждый обспечивает ее самостоятельно.
Технологическое разнообразие: С микросервисами легко смешивать языки программирования, среды разработки и технологии хранения данных. Сложность эксплуатации: Для управления микросервисами, которые регулярно переразвертываются, требуется зрелая группа эксплуатации/поддержки.

Перейти к итогам.

Жесткие границы модулей

Первое преимущество микросервисов – жесткие границы модулей. Это важное, но давольно странное преимущество, поскольку в теории непонятно, почему микросервисы должны иметь более жесткие границы модулей, чем монолитный код.

Так что же я имею в виду под жесткими границами модулей? Я думаю вы согласитесь, что разделение ПО на модули (фрагменты программного кода, которые отделены друг от друга) – полезное занятие. Если мне требуется изменить систему, то я разбираюсь как работает только небольшая ее часть. И найти эту часть давольно легко.

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

Сторонники микросервисов сразу вспоминают закон Конвея (Conways Law), согласно которому система отражает коммуникационную структуру организации, в который она разрабатывалась.

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

Как сказано выше, нет никаких причин считать, что монолитная система не может иметь хорошую модульную структуру. Но мы то знаем, что это случается крайне редко, а самая распространенная архитектурная концепция у монолитных систем – «запутанный клубок» (Big Ball of Mud), который все чаще становится причиной для разворота в сторону микросервисов.

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

Другой аспект – постоянные данные. Одна из ключевых характеристик микросервисов — децентрализованное управление данными, согласно которому каждый сервис использует свою собственную БД и любые другие сервисы получают к ним доступ только через API сервиса-владельца данных. Это устраняет интеграционные базы данных, которые выступают основным источником вредных связей в больших системах.

Еще раз подчеркну, что существование четких границ модулей возможно и в монолитном коде, но это требует дисциплины. Аналогично «запутанный клубок» может состоять и из микросервисов, но в этом случае потребуется больше усилий.

Я смотрю на это так – использование микросервисов повышает вероятность получить лучшую модульность системы. Если вы уверены в дисциплине коллег, то это преимущество незначительно. Но по мере роста команды поддерживать дисциплину станет сложнее.

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

Но я еще не закончил с оговорками по этому вопросу. Сказать, насколько хорошо система поддерживает модульность, можно только по прошествии времени. То есть, у систем, просуществовавших хотя бы пару лет.

Кроме того, ранние адепты новых идей обычно более талантливы, что даёт дополнительную задержку для оценки модульных преимуществ микросервисных систем, написанных средними командами разработчиков.

Но даже и тогда мы обязаны признать, что средние команды пишут среднее программное обеспечение, поэтому вместо сравнения результатов с топ-командами лучше сравнить полученное программное обеспечение с тем, как оно же выглядело бы в монолитной архитектуре, а это непростая гипотетическая ситуация для сравнения.

Все, что сейчас можно сказать основано на свидетельствах людей, которых я знаю, и которые использовали этот стиль. Они говорят, что им поддерживать модули с микросервисами значительно легче.

Один пример будет особенно интересен. Команда сделала неправильный выбор, используя микросервисы для системы, которая не была достаточно сложна, чтобы оправдать издержки микросервисов. Проект попал в беду и нуждался в спасении. На это было брошено намного больше людей, чем планировалось изначально.

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

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

Распределенность


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

Как только вы выбираете распределенность, получите в догонку букет сложностей.

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

Если сервис вызывает пять удаленных сервисов, каждый из которых вызывает еще пять удаленных сервисов, то общее время задержки может стать пугающим. Конечно, для смягчения этой проблемы придуман не один способ.

Во-первых, можно делать меньше удаленных вызовов, увеличив их детализацию, но это усложняет модель программирования, так как теперь нужно думать о том, как объединять взаимодействия между сервисами. У этого подхода тоже есть лимит – каждый взаимодействующий сервис всё равно потребуется вызвать хотя бы один раз.

Второй подход к смягчению проблемы — асинхронный подход. Если сделать шесть асинхронных вызовов одновременно, то общее время ожидания будет определяться самым медленным вызовом, а не суммой всех.

Это может дать большой выигрыш в производительности, но влечет другую проблему – асинхронность сложно программировать и ещё труднее отлаживать.

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

Следующий пункт после скорости — надежность.

Вы ожидаете, что внутренние вызовы функций всегда будут работать, но удаленный вызов может отказать в любой момент. С ростом количеством микросервисов потенциальных точек отказа становится больше. Мудрые разработчики знают это и проектируют с учетом отказов. К счастью техники, которые нужны для реализации асинхронного взаимодействия, также хорошо подходят для работы с отказами, повышая отказоустойчивость.

Однако, это не полная компенсация, т.к. по-прежнему остаются дополнительные сложности по выявлению последствий отказа для каждого внешнего вызова. И это только две основные проблемы распределенных вычислений.

Несколько комментариев к этому. Во-первых, озвученные проблемы возрастают в монолитных системах по мере их роста. Мало монолитных систем действительно самодостаточных. Как правило, существуют прочие системы, с которыми приходится взаимодействовать.

Взаимодействие с ними происходит по сети и мы сталкиваемся с теми же проблемами. Именно поэтому команды, которые работают с удаленными системами, склонны быстрее переходить на микросервисы. В этом вопросе сильно помогает опыт — более умелые команды лучше справляются с проблемами распределенности.

Резюмируя, распределенность добавляет сложность и затраты. Я неохотно принимаю решение об ее использовании и считаю, что слишком часто люди недооценивают связанные с этим проблемы.

Мастер Йода рекомендует:  Подборка фреймворков и инструментов для iOS-разработчика 2020

Согласованность в конечном счете

Я уверен, что вы знаете веб-сайты, которые требуют терпения. Вы изменяете что-то, экран обновляется, но ваше изменение отсутствует. Вы ждете одну-две минуты, обновляете экран снова и, наконец, видите свои изменения.

Это очень раздражающая проблема юзабилити, и она почти всегда связана с согласованностью кода. Ваше изменение было получено розовым узлом (Pink node), но запрос Get был обработан зеленым узлом (Green node). До тех пор, пока зеленый узел не получит обновление от розового, сохраняется ситуация несогласованности. В конечном счете согласованность достигается, но до тех пор можно подумать, что что-то пошло не так.

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

Микросервисы подвержены проблеме несогласованности из-за их достойной уважения настойчивости на децентрализованном управлении данными. В монолитной системе можно обновить множество объектов в одной транзакции. С микросервисами потребуется несколько ресурсов для обновления и распределенные транзакции не одобряются (по веским причинам). Как результат, теперь разработчики должны помнить о возможности несогласованности и думать о том, как определять моменты рассинхронизации, прежде чем программировать что-то, о чем потом можно будет пожалеть.

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

Так же, как с другими проблемами распределенности, монолитные системы не полностью избегают несогласованности, но они страдают от этого гораздо меньше, особенно, когда они небольшие.

Независимое развертывание

Компромисс между границами модулей и сложностями распределенных систем присутствовал в течение всей моей карьеры.

Но одна вещь, которая заметно изменилась только в последнее десятилетие — развертывание production-окружения.

В двадцатом веке поставка новых версий ПО была почти повсеместно болезненным и редким событием, когда во время выходных все пытались поместить какой-то странный кусок программного обеспечения туда, где он может сделать что-то полезное.

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

Этот сдвиг оказал глубокое влияние на индустрию программного обеспечения, и он тесно переплетен с движением сторонников микросервисов.

Использование микросервисов в том числе было вызвано сложностью развертывания больших монолитных систем, где небольшое изменение в части системы может привести к неудаче всего развертывания.

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

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

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

Вот почему быстрое развертывание приложений и быстрое выделение ресурсов инфраструктуры являются предварительными требованиями для использования микросервисов.

Для хоть сколь-нибудь сложных систем вы должны использовать непрерывную поставку. Большим преимуществом непрерывной поставки является сокращение цикла от идеи до работающего программного обеспечения.

Организации, которые делают это, могут быстро реагировать на изменения рынка, а также вводить новые функции быстрее конкурентов.

Хотя многие люди указывают непрерывную поставку в качестве причины для использования микросервисов, важно отметить, что непрерывная поставка может применяться даже для крупных монолитных систем. Facebook и Etsy — два наиболее известных примера.

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

Хотя от многих людей я слышу, что гораздо проще сделать непрерывную поставку при использовании микросервисов, я менее убежден в этом по сравнению с их практической пользой для модульности — хотя, естественно, модульность сильно коррелирует со скоростью поставки.

Сложность эксплуатации

Возможность быстро развернуть небольшие независимые единицы кода является большим благом для разработчиков, но это создает дополнительную нагрузку на эксплуатацию, поскольку пять больших приложений превращаются в сотни маленьких микросервисов.

Организации считают поддержку такого количества быстро меняющихся элементов непомерно высокой нагрузкой.

Это подчеркивает важность непрерывной поставки. Она — ценный навык для монолитов, затраты на который почти всегда окупаются, но для серьезного проекта на микросервисах это жизненная необходимость.

Вы просто не сможете справиться с десятками сервисов без автоматизации и совместной работы, входящих в непрерывную поставку. Эксплуатационная сложность увеличивается также в связи с повышением требований к управлению этими сервисами и их мониторингу.

Опять же это уровень зрелости, который полезен для монолитных приложений и необходим, если появляются микросервисы.

Сторонники микросервисов говорят, что поскольку каждый сервис небольшой, его проще понять. Но опасность заключается в том, что сложность не устраняется, она просто смещается на взаимосвязи между сервисами.

Это может маскировать увеличение сложности эксплуатации, например, трудности при отладке функций, которые включают несколько сервисов. Хороший выбор границ сервисов уменьшает эту проблему, а неправильный выбор границ делает её гораздо сложнее.

Решение таких эксплуатационных проблем требует множества новых навыков (в большей степени) и инструментов. Инструменты пока ещё не достигли зрелости, но мой опыт подсказывает мне, что даже при наличии лучших инструментов нижний порок по навыкам в среде микросервисов выше.

Тем не менее, эта потребность в навыках и инструментах не является самой сложной частью проблем эксплуатации. Для эффективной работы нужно ввести культуру DevOps: более тесное сотрудничество между разработчиками, службой эксплуатации и всеми остальными участниками процесса поставки.

Культурные изменения трудны, особенно в больших и давно существующих организациях. Если вы не сделаете эти культурные изменения и не повысите навыки разработчиков, ваши монолитные приложения будут испытывать небольшие проблемы, но ваши приложения на базе микросервисов серьезно пострадают.

Технологическое разнообразие

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

Микросервисы могут быть написаны на разных языках, использовать разные библиотеки и различные хранилища данных. Это позволяет командам выбрать подходящий инструмент для работы, так как некоторые языки и библиотеки лучше подходят для определенных задач.

Обсуждение технического разнообразия обычно сосредотачивается на выборе лучшего инструмента для работы, но часто большим преимуществом микросервисного подхода является возможность использования разных версий.

В монолитной системе вы можете использовать только одну версию библиотеки, что часто приводит к проблемам при обновлениях.

Одной части системы может потребоваться обновление библиотеки, чтобы использовать свои новые возможности, но это нельзя сделать, так как такое обновление ломает другую часть системы.

Работа с версиями библиотек является одной из тех проблем, которые экспоненциально растут по мере роста количества кода. Существует опасность того, что с таким технологическим разнообразием компания-разработчик может быть перегружена.

Большинство организаций, которых я знаю, поощряют ограниченный набор технологий. Это поощрение поддерживается путем предоставления общих инструментов для таких вещей, как мониторинг. В результате сервисы проще делать в небольшом портфеле общих сред разработки.

Не стоит недооценивать важность поддержки экспериментов. В монолитной системе ранние решения о языках и средах разработки трудно изменить. После десяти лет или около того такие решения могут загнать команды разработчиков в рамки неудобных технологий.

Микросервисы позволяют командам экспериментировать с новыми инструментами, а также постепенно мигрировать системы по одному сервису за раз, когда актуальной становится другая технология.

Второстепенные факторы

Я рассматриваю указанные выше моменты как основные. Вот еще несколько вещей, которые, как я думаю, менее важны.

Сторонники микросервисов часто говорят, что сервисы проще масштабировать, так как если один сервис получает слишком большую нагрузку, то можно масштабировать только его, а не все приложение.

Однако я не могу вспомнить реальный проект, который убедил бы меня, что было на самом деле более эффективно делать это избирательное масштабирование по сравнению с типовым масштабированием путем копирования полного приложения.

Микросервисы позволяют отделить конфиденциальную информацию и добавить к ней больше безопасности. Кроме того, если защитить весь трафик между микросервисами, злоумышленникам будет сложнее использовать уязвимости.

По мере роста важности проблем безопасности это может стать одной из главных причин использования микросервисов. Даже без этого в преимущественно монолитных системах часто создают отдельные сервисы для обработки конфиденциальных данных.

Самое главное здесь — иметь дисциплину, чтобы относиться к тестированию серьезно, так как на самом деле различия между тестированием монолитных приложений и приложений на базе микросервисов не столь существенны.

Итоги

Любая общая статья об архитектурных подходах ограничивается общими рекомендациями.

Статьи, подобные этой, не дадут вам готовых решений, но они могут помочь в рассмотрении факторов, которые стоит учитывать. Каждое преимущество и недостаток будет иметь различный вес для различных систем.

Иногда преимущество станет недостатком и наоборот (например, жесткие границы модулей хороши в сложных системах, но излишняя нагрузка для простых).

Решения, которое вы принимаете, зависят от применения таких критериев к вашей ситуации, оценки факторов критических для вашей системы и того, как они влияют на результаты.

Кроме того, опыт микросервисных архитектур относительно невелик. Обычно взвешенные выводы по архитектуре можно делать только после того, как эта архитектура созрела, и вы узнали, каково в ней работать через годы после начала разработки. Пока у нас не много примеров долгоживущих микросервисных архитектур.

Монолит vs. Микросервисы — сложный выбор из двух вариантов. Оба являются нечеткими определениями, и многие системы оказываются в размытой граничной области. Также есть другие системы, которые не вписываются ни в одну из этих категорий.

Большинство людей, включая меня, противопоставляют микросервисы монолитным системам, потому что имеет смысл сравнивать их с более традиционным подходом, но мы должны помнить, что существуют системы, которые нельзя четко отнести ни к микросервисам, ни к монолитам.

Я рассматриваю монолитные системы и микросервисы как две области в пространстве архитектур. Их стоит выделять, потому что они обладают интересными характеристиками, которые полезны для обсуждения, но ни один разумный архитектор не рассматривает их в качестве полного разбиения архитектурного пространства.

Тем не менее, один общий вывод, который, как кажется, признается большинством — издержки микросервисов: микросервисы более трудоемки, и это окупается только для более сложных систем. Поэтому, если вы можете справиться со сложностью вашей системы с помощью монолитной архитектуры, вам не следует использовать микросервисы.

Говоря о микросервисах, давайте не забывать о более важных вопросах, которые определяют успех или провал проектов разработки ПО. Такие факторы, как качество людей в команде, насколько хорошо они взаимодействуют друг с другом, насколько они общаются с экспертами в предметной области, будут иметь большее влияние на проект, чем использование или не использование микросервисов.

На чисто техническом уровне важнее сосредоточить внимание на таких вещах, как чистый код, хорошее тестирование и внимание к развитию архитектуры.

Микросервисы или монолит: в поисках золотой середины

Всегда приятно начинать новый проект. Простые классы, четкие границы, ясная архитектура — все логично и красиво. Новая функциональность добавляется легко и быстро.

Идет время, проект развивается, поступают новые требования. Но приходит день, когда вы обнаруживаете в коде что-то плохое. Кто-то срезал угол и сделал небольшой костыль. Бывает, что вы сами делаете что-то на скорую руку, честно вставляя в код “todo” — просто потому, что эта функциональность нужна для ближайшего релиза, а времени сделать все правильно нет. “Это технический долг, который мы обязательно исправим после очередного релиза, но сейчас надо выдать версию” — произносим мы при этом.

Нет ничего более постоянного, чем временное — очень справедливые слова. Чаще всего бывает, что дальше технический долг будет только нарастать. Так же, как обслуживание долга в банке требует выплаты процентов, наличие технического долга забирает свой процент. Мы платим за это увеличивающейся сложностью внесения изменений, нарастающей неочевидностью и нелогичностью модели, изчезающим энтузиазмом команды.

В определенный момент становится понятно, что история повторилась и у нас в руках очередной “большой ком грязи”. Что же делать и можно ли этого избежать?


В настоящее время многие видят ответ в микросервисной архитектуре. В самом деле, наличие четких физических границ, например, не позволит срезать углы так, как это было бы сделано в случае монолита.

Но у микросервисного подхода есть своя цена, проистекающая из распределённого характера такой системы. Там, где раньше все происходило в одном процессе, теперь межсерверное взаимодействие, с передачей данных по сети, сопровождающейся сериализацией/десериализацией данных. Там, где раньше была транзакционая целостность, теперь событийная консистентность. Вместо синхронных вызовов, с понятным результатом, теперь асинхронное обращение к нескольким узлам, каждое из которых может вернуться с ошибкой или отвалиться по таймауту… И много других, неочевидных на первый взгляд, но непременных спутников распределённых систем. В конце концов, начиная новый проект нам может быть сложно правильно разделить будущую систему на микросервисы, просто потому, что мы не знаем как будет развиваться система. А пытаться продумать архитектуру наперед может оказаться малопродуктивным занятием.

В целом, при разработке с нуля нового проекта на основе микросервисов, не покидает ощущение стрельбы из пушки по воробьям. Система еще не выглядит такой сложной, чтобы применять деление на подсистемы.

Очевидно, в развитии системы возникает момент, когда цена микросервисов окупается за счёт уменьшения издержек от снижения производительности команды при усложнении системы. Мартин Фаулер (Martin Fowler) хорошо проиллюстрировал этой в своей заметке Microservice Premium :

Также хорошо видно, что для проектов малой и средней сложности монолитный подход более выигрышен в плане производительности команды. А ведь это как раз тот этап, когда зачастую определяется, пойдёт ли проект в большую жизнь. Например, в случае стартапа или proof-of-concept проекта. Тратить на этом этапе ресурсы, забирая их у разработки фич может привести к тому, что эта большая жизнь и не придет. А если проект не выстрелит, то ресурсы просто будут выброшены.

Вот если бы можно было развиваться по кривой монолита на низкой и средней сложности проекта, а потом перескочить на кривую микросервисов и продолжить развивать систему большой сложности уже на ней.

К сожалению, такого подхода ещё не изобрели. Но зато, есть другой — который вполне может претендовать на звание “золотой середины”. Речь ниже пойдёт о модульной организации и связанных с этим преимуществах.

Если попробовать сравнить модульный и микросервисный подходы, то можно выделить следующие характеристики:

Характеристика Модули Мсервисы
Декомпозиция и строгие границы + +
Возможность наличия собственной БД + +
Простота рефакторинга и перенос границ +
Отсутствие накладных расходов на networking +
Отсутствие накладных расходов на инфраструктуру +
Типизация и проверка компилятором передаваемых данных +
Проверка компонентных зависимостей на этапе компиляции +
Поддержание схемы взаимодействия компонентов в явном виде +
Синхронное взаимодействие +
Возможность выполнения транзакций между компонентами +
Использование разных языков для разных компонентов +
Независимое развертывание / раздельные процессы (

отказоустойчивость)

+
Возможность независимого масштабирования компонентов +
Различный жизненный цикл для разных компонентов +

Итак, мы хотим разделить нашу системы на части, определив интерфейсы на границах, которые будут обеспечивать контракты взаимодействующих компонентов. В принципе, мы могли бы попробовать ввести соответствующее разделение на пакеты (java packages). Но быстро станет ясно, что это не поможет в соблюдении границ, так как достаточный уровень инкапсуляции при этом не обеспечивается. Всегда можно обратится к любому public классу в обход интерфейса. А с помощью reflection API можно получать доступ даже к private методам/полям. Это приводит к тому, что части приложения взаимодействуют уже не на основе контрактов, а на основе знания о внутреннем устройстве друг друга. При этом любое изменение, даже не меняющее контракт компонента, будет ломать все зависящие от него компоненты.

Как же обеспечить строгую инкапсуляцию? С одной стороны, для Java платформы уже давно существует индустриальный стандарт компонентной архитектуры приложения OSGi , который решает эту задачу и даже позволяет динамическую загрузку/выгрузку компонентов без перезапуска JVM. На его основе реализован ряд систем . Однако, за долгие 17 лет существования он не пошёл в массы, возможно по причине своей сложности , которая не позволяет кардинально снизить издержки по сравнению с теми же микросервисами.

Хорошая новость в том, что в рамках грядущей Java 9 запланирована реализация модульной системы на уровне JVM . Это, с одной стороны, позволит модуляризовать саму Java-платформу, а с другой — предоставит конструкцию, обеспечивающую строгое соблюдение границ модулей как при компиляции, так и во время исполнения.

В целом, при правильном применении этого подхода, можно будет говорить о модулях как о микросервисах без HTTP и внутри JVM. Для такой системы, видимо, будет справедлива картинка:

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

Пост был опубликован: Среда, Май 17th, 2020 в 4:31 пп

Современная веб-архитектура. От монолита к микросервисам

Архив номеров / 2020 / Выпуск №1-2 (170-171) / Современная веб-архитектура. От монолита к микросервисам

АЛЕКСАНДР КАЛЕНДАРЕВ, 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.

    1. Сэм Ньюман. Создание микросервисов. – O’Reilly, 2020.
    2. Грогор Хоп, Бобби Вульф. Шаблоны интеграции корпоративных приложений. – М.: Вильямс, 2007.

    Что предпочтительней — SOA или микросервисы?

    Многие рассматривают микросервисы как результат эволюции сервис-ориентированной архитектуры (Service Oriented Architecture, SOA), считая их новым поколением SOA. Однако это не совсем так. Хотя технология микросервисов действительно построена на базе SOA, в ней кое-чего не хватает.

    Как утверждает независимый консультант и программный архитектор из Бостона Марк Ричардс в онлайновой брошюре «Microservices vs Service Oriented Architecture», между этими архитектурами есть различия, которые следует учитывать в каждой конкретной ситуации при выборе подходящего решения.

    Архитектура микросервисов — восходящая звезда на ИТ-небосклоне. Раньше считалось, что создание приложения из множества сервисов является сложной, чреватой ошибками задачей, за последние несколько лет ситуация коренным образом изменилась в основном благодаря развитию контейнерных платформ и принципов DevOps, направленных на автоматизацию и масштабируемость. По мнению Ричардса, эти концепции тесно связаны. Хотя организации могут реализовать DevOps без микросервисов, не следует внедрять микросервисную архитектуру без культуры DevOps.


    Однако годятся ли микросервисы на все случаи жизни? Ричардс уверен, что нет, так как зачастую оказывается, что более целесообразно применить SOA. Основное различие между этими подходами заключается в том, что микросервисная архитектура построена по принципу «как можно меньше совместно используемых элементов», а SOA, наоборот, использует принцип «как можно больше совместно используемых элементов», в котором основной акцент сделан на абстрагировании и повторном использовании бизнес-логики.

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

    Микросервисы — более гранулированные и менее монолитные, чем традиционная SOA. Их проще и быстрее реализовать. К тому же они не зависят от формальных, медленно развивающихся отраслевых спецификаций, т. к. создаются с помощью API и HTTP.

    Тем не менее, Ричардс считает, что у микросервисов отсутствуют некоторые базовые возможности, имеющиеся у SOA. Поэтому чем крупнее и масштабнее инфраструктура, тем вероятнее, что для нее больше подходит сервис-ориентированная архитектура. В качестве примера он привел ряд возможностей, из-за которых в ряде случаев целесообразнее применять традиционную SOA.

    Разделение контракта (contract decoupling). Разделение контракта позволяет сервису и его потребителям развиваться отдельно, но сохранять контракт. По словам Марка Ричардса, могут возникнуть осложнения, когда данные, передаваемые потребителем сервиса, отличаются от того, что ожидает получить соответствующий сервис. SOA обеспечивает согласование данных.

    Микросервисная архитектура не поддерживает разделение контрактов, хотя это является одной из главных возможностей SOA. Поэтому тем, кому нужен высокий уровень абстракции, следует для реализации приложения или системы воспользоваться решением на базе SOA, а не микросервисов.

    Совместимость в случае неоднородности. SOA лучше подходит для интеграции со множеством неоднородных систем и сервисов. По словам Ричардса, микросервисный подход направлен на упрощение архитектуры и ее реализации за счет сокращение числа возможностей для интеграции сервисов.

    Приложения корпоративного масштаба. SOA хорошо подходит для больших, сложных систем масштаба предприятия, для которых требуется интеграция с множеством неоднородных приложений и сервисов. Эта архитектура также пригодится при создании приложений, имеющих много совместно используемых компонентов, особенно таких, которые совместно используются в масштабе всего предприятия. Микросервисы, у которых отсутствует связующее ПО, больше подходят для небольших, легко разделяемых веб-систем, чем для систем масштаба предприятия.

    Пара слов в защиту монолита

    Сравниваем особенности микросервисной и монолитной архитектуры, их преимущества и недостатки. Статья подготовлена для Хабра по материалам нашего митапа Hot Backend, который прошел в Самаре 9 февраля 2020 года. Мы рассматриваем факторы выбора архитектуры в зависимости от конкретной задачи.

    Еще лет 5 назад никто и не слышал о микросервисах. Однако, их популярность увеличивается из года в год, согласно статистике Google Trends.

    Монолит и микросервисы: примеры

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

    Микросервисная архитектура предполагает разбивку на модули, которые запускаются как отдельные процессы и могут иметь отдельные серверы. Каждый микросервис работает со своей базой данных, и все эти сервисы могут общаться между собой как синхронно (http), так и асинхронно. При этом для оптимизации архитектуры желательно минимизировать взаимосвязи между сервисами.

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

    Микросервисы: преимущества

    Можно выделить как минимум четыре плюса микросервисной архитектуры:

    Независимое масштабирование и развертывание

    Для каждого микросервиса предусмотрен независимый деплой, и это удобно при обновлении отдельных модулей. Если нагрузка на модуль возрастает, соответствующий микросервис можно масштабировать, не затрагивая остальные. Это позволяет гибко распределять нагрузку и экономить ресурсы.

    Каждый микросервис (например, модуль памяти) можно разработать силами одной команды, чтобы увеличить скорость создания программного продукта.

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

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

    В среде разработчиков можно услышать мнение, что монолитная архитектура устарела, ее сложно сопровождать и масштабировать, она быстро разрастается в “большой ком грязи” и практически является антипаттерном, то есть ее наличие в коде нежелательно. В качестве доказательства этого мнения зачастую приводятся крупные компании, например, Netflix, которые перешли на микросервисную архитектуру в своих проектах.

    Давайте разберемся, действительно ли всем следует переходить от монолита к микросервисам по примеру крупнейших брендов?

    Переход на микросервисы: возможные затруднения

    Проблема первая: декомпозиция

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

    Если возникает необходимость перенести часть функций из сервиса А в сервис Б, то здесь возможны затруднения: например, сервисы выполнены на разных языках, внутренние вызовы сервисов становятся сетевыми, нужно подключать другие библиотеки. Проверить правильность рефакторинга мы можем только с помощью тестов.

    Проблема вторая: транзакции

    Еще одна проблема связана с тем, что у микросервисов нет понятия распределенных транзакций. Мы можем гарантировать архитектурную целостность бизнес-операции только в рамках одного микросервиса. Если операция затрагивает несколько микросервисов, там могут быть использованы разные базы данных, и от такой транзакции придется отказаться. Для решения этой проблемы есть разные методы, используемые в бизнесе, когда доступность оказывается важнее, чем целостность. При этом предусматривают компенсирующие механизмы на случай, если что-то пойдет не так. Например, если товара нет на складе, нужно осуществить возврат денег на счет покупателя.

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

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

    Проблема третья: построение отчетов

    Если мы используем монолитную архитектуру с единой базой данных, для построения сложного отчета можно написать select и подтянуть несколько табличек с данными: рано или поздно они будут выведены. Однако, на микросервисах эти данные могут быть раскиданы по разным базам.

    Например, нам нужно вывести список компаний с определенными метриками. При выводе простого списка компаний все работает. А если нужно добавить метрики, которые лежат в другой базе данных? Да, мы можем сделать дополнительный запрос и по ИНН запросить метрики. А если этот список нужно фильтровать и сортировать? Список компаний может оказаться очень большим, и тогда нам приходится вводить дополнительный сервис со своей базой данных — отчеты.

    Проблема четвертая: высокая сложность разработки

    Работа над распределенными сервисами сложнее: все запросы осуществляются по сети и могут «заглючить», нужно предусмотреть callback механизм (будет ли он осуществлять вызов повторно? Сколько раз?). Это «кирпичики», которые постепенно накапливаются и вносят свой вклад в увеличение сложности проекта.

    Сервисы могут быть разработаны несколькими разными командами, и нужно документировать их, поддерживать документацию в актуальном состоянии, предупреждать другие команды при смене версии. Это дополнительные трудозатраты.

    Если у каждой команды независимый деплой, нужно поддерживать как минимум предыдущую версию и отключать ее только после того, как все потребители сервиса перейдут на новое API.
    Конечно, мы можем вынести все API в некий артефакт, который будет общедоступен. Но, во-первых, сервисы могут быть написаны на разных языках, во-вторых, так делать не рекомендуется. Например, в одном из наших проектов мы отказались от этого по желанию заказчика, связанному с соображениями безопасности. Каждый микросервис имеет отдельный репозиторий, причем заказчик не дает доступ к ним.

    В процессе разработки все может работать корректно, а потом – нет. Бывает, что в случае возникновения исключений приложение бесконечно пытается их обработать, и это дает большую нагрузку – вся система «ложится». Чтобы избежать таких ситуаций, нужно все настроить, например, ограничить количество попыток, не возвращать это обращение в очередь в ту же секунду и т.д.

    Проблема пятая: сложность тестирования, трассировки и отладки

    Чтобы протестировать какую-либо проблему, нужно скачать все задействованные микросервисы. Отладка становится нетривиальной задачей, а все логи нужно собирать где-то в одном месте. При этом логов нужно как можно больше, чтобы разобраться, что случилось. Для отслеживания проблемы нужно понять весь путь, который прошло сообщение. Юнит-тестов здесь недостаточно, поскольку вероятны ошибки на стыке сервисов. При внесении изменений убедиться в работоспособности можно только после прогона на стенде. Мы можем ограничить каждый микросервис некоторым объемом памяти (например, 500 мегабайтов), но бывают моменты пиковой нагрузки, когда потребуется до двух гигабайтов. Бывают моменты, когда система начинает тормозить. В результате ресурсы могут расходоваться на то, что не относится к непосредственным задачам клиента: к примеру, есть всего два бизнесовых микросервиса, а половина ресурсов расходуется на три дополнительных микросервиса, поддерживающих работу остальных.

    Микросервис или монолит: критерий выбора

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

    Если предметная область простая, а глобального прибавления количества пользователей не ожидается, то можно без сомнений использовать микросервисы. В остальных случаях лучше начинать разработку на монолите и сэкономить ресурсы, если масштабирование не потребуется. Если предметная область сложная, а на начальном этапе не определены окончательные требования, тоже лучше начинать с монолита – чтобы не переделывать микросервисы по несколько раз. При дальнейшем развитии проекта можно выделить отдельные его части в микросервисы.

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

    У каждого модуля должен быть свой API, чтобы впоследствии его можно было выделить и сделать модуль микросервисом.

    Определив границы модулей, можно переходить к декомпозиции на микросервисы, если это понадобится. Примерно в 90% случаев можно будет остаться на монолите, но при необходимости вам будет легче и дешевле изменить архитектуру.

    В нашей практике работы с монолитом и микросервисами мы пришли к следующим выводам:

    • Не переходите на микросервисы только потому, что их используют Netflix, Twitter, Facebook
    • Начните с двух-трех микросервисов, которые взаимодействуют друг с другом, детально проработайте на них все нефункциональные требования (безопасность, отказоустойчивость, масштабируемость и т.п.) и только потом переходите к остальным сервисам
    • Автоматизируйте все, что только возможно
    • Настройте мониторинг
    • Пишите автотесты
    • Не используйте распределенные транзакции (но это не повод отказаться от гарантии целостности данных).
    • Если вы хотите использовать микросервисную архитектуру, будьте готовы к тому, что разработка может обойтись вам примерно в 3 раза дороже, чем на монолите. Однако, обе технологии имеют свои недостатки и преимущества, у каждой из них есть своя ниша.

    Когда оправдано использование микросервисной архитектуры

    Микросервисы – это разновидность сервис-ориентированной архитектуры (SOA), применяемая для формирования распределенных программных систем. Модули в микросервисной архитектуре взаимодействуют по сети, при этом выполняя единую цель. На данный момент микросервисы постепенно вытесняют монолитные приложения и превращаются в стандарт развития программных систем.

    Важно понимать, что под сервисом понимается целый набор услуг и определенный функционал, который предоставляют потребителю. А микросервисы – это дробление функционала так, чтобы он был доступен другим частям системы. Причем дробление функционала настолько мелкое, что внутри каждого микросервиса реализовано совсем маленькое количество функций.

    Микросервисная архитектура – это несколько функциональных модулей, взаимодействующих через сеть

    Принципиальное отличие микросервисной архитектуры от монолитной

    Микросервисная архитектура приложения родилась из монолитной архитектуры, когда та стала сложной и неудобной в работе. Главное отличие микросервисов от монолита – в использовании специализированных более простых программ (модулей) при выполнении сценария приложения. Тогда как в монолитной архитектуре использовались внутрипроцессные взаимодействия. И, что самое удобное, модули могут находиться на разных серверах и их взаимодействие происходит через сеть по протоколонезависимой технологии.

    Микросервисная архитектура имеет ряд преимуществ перед монолитной:

    • симметричная архитектура (в монолитных приложениях – иерархическая);
    • взаимозаменяемость микросервисов;
    • независимость микросервисов друг от друга;
    • организация модулей вокруг отдельных функций;
    • написание микросервисов с помощью любых программных средств, оптимальных для каждого конкретного модуля, при этом они хорошо «понимают» друг друга благодаря интерфейсу. Создание интерфейса является наиболее сложной задачей;
    • микросервисы вызываются только потребителем, но не друг другом.

    Различие микросервисной и монолитной архитектуры

    Каждый микросервис – это небольшая монолитная программа, которая выполняет свою функцию. В программный продукт при разработке микросервисной архитектуры можно добавлять любое количество новых микросервисов, расширяя его функциональность. Чтобы добиться подобного в монолитной программе, необходимо вносить изменения в основной продукт.

    Принцип работы микросервисной архитектуры можно рассмотреть на бытовом примере. Допустим, мы решили воспользоваться таким сервисом, как химчистка. Мы отдаем вещь, а через время получаем ее назад чистой, выглаженной и готовой к использованию, не задумываясь о том, как это достигается и какие сервисы выполняются внутри химчистки. А таких сервисов много: принять вещь, положить в стиральную машину, запустить стирку, достать вещь, погладить, выдать и так далее.

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

    Монолитная архитектура не справлялась с потребностью бизнеса ускоряться, так как крупные сервисы сложно быстро изменять и адаптировать. Чтобы добиться ускорения, разумным решением стало создание типовых микросервисов, по-разному реализованных в крупных сервисах и выделенных в самостоятельные компоненты. Теперь каждый крупный сервис может пользоваться микросервисами по необходимости. А так как отпала нужда в дублировании типовых функций, это сделало программы более легкими и гибкими.

    При микросервисной архитектуре приложения можно обновлять ПО частями, что гораздо проще и безопаснее, чем обновление «монолита». Приложение не выйдет из строя, если произойдет сбой одного или нескольких микросервисов.

    Причины возникновения микросервисной архитектуры

    О проблеме в использовании монолитных приложений впервые заговорили в 2005 г. на конференции Cloud Computing. Большие цельные программы стали слишком неудобными в разработке, не давали нужной скорости внедрения и функциональности, сложно тестировались и долго вводились в эксплуатацию. Они не позволяли быстро вносить поправки и оперативно реагировать на изменения бизнес-требований.

    Уже тогда микросервисы назвали новой ступенью развития архитектуры, которая обеспечит приложениям необходимую гибкость и легкость. Термин «микросервисы» закрепился в 2011 г. при разработке программного обеспечения, содержащего модули, – но это больше относится к SOA. В 2012 г. термин был принят окончательно, но значение, которое мы используем сегодня, приобрел недавно.

    Микросервисы в современном понимании имеют следующие особенности:

    • легкость и простота: каждый модуль выполняет уникальную функцию и имеет небольшой размер;
    • конечность, атомарность;
    • гибкость: модуль можно легко изменить, добавив в его работу необходимые опции;
    • взаимозаменяемость;
    • полиморфизм;
    • комбинирование микросервисов для реализации разных функций.

    Микросервисная архитектура устранила недостатки монолитного ПО, обеспечив:

    • изоляцию и минимизацию изменений;
    • ускорение разработки;
    • возможность легко подстраивать ПО под структуру бизнеса.

    Необходимость ускорения работы

    Одна из ключевых особенностей современного бизнеса – динамичность. Кто первым вышел на рынок, тот и получает конкурентное преимущество. Кто быстрее вносит необходимые изменения и внедряет улучшения, тот получает большую долю рынка. Все это приводит к тому, что необходимо искать пути ускорения работы, в том числе и программных продуктов.

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

    Если ранее монолитные сервисы реализовывали конкретные бизнес-функции, то сегодня микросервисы самостоятельных бизнес-функций не несут. Огромный плюс такой архитектуры в том, что можно реализовывать новые бизнес-функции, используя набор существующих микросервисов. Это преимущество микросервисного подхода объясняет его востребованность. Кроме того, каждый модуль можно строить индивидуально с использованием оптимальных средств разработки.

    Разделяя «монолит» на микросервисы, девелопер получает возможность распараллеливания разработки, что значительно сокращает сроки выполнения.

    Компоненты микросервисной архитектуры разрабатываются и работают параллельно

    Когда разные модули разработаны, остается просто собрать их в единую систему. При этом каждый отдельный микросервис легко трансформировать в соответствии с меняющимися требованиями рынка, не мешая при этом работе всего приложения.


    Быстрый ввод в эксплуатацию

    Отладка работы ПО с микросервисной архитектурой – более быстрый процесс, чем отладка работы «монолита». Разработчик легко может отслеживать взаимодействие между разными микросервисами, быстрее находить и устранять ошибки.

    Это позволяет в короткие сроки реализовать крупные программные продукты. Независимая эволюция подсистем дает возможность совершенствовать продукт, не изменяя при этом его сути.

    Микросервисы обеспечивают эффективный подход к разработке, который дает возможность:

    • разрабатывать одно приложение нескольким автономным командам;
    • использовать разные стеки по необходимым задачам для единого продукта;
    • осуществлять децентрализованное управление данными, если это требуется для бизнеса.

    Необходимость подстраивать сервис под структуру бизнеса

    С изменением структуры бизнеса почти всегда возникает необходимость в подстройке ПО под новые требования. Внесение изменений и последующая отладка монолитного программного обеспечения – трудоемкая задача. И сроки подстройки пропорциональны размерам и сложности приложения.

    Но если бизнес изменился и в нем добавились новые функции, уже не нужно полностью переделывать старую программу или заказывать новое ПО. Достаточно создать несколько новых микросервисов, которые помогут реализовать необходимые задачи. Это быстро, дешево и удобно.

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

    Перспективы использования микросервисов в бизнесе

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

    Дополнительным плюсом использования микросервисов для реализации бизнес-функций является их одинаковая работа в разных системах. Например, используя в разных системах один и тот же микросервис, выдающий паспортные данные клиента по запросу, мы везде получим идентичный результат в одинаковом виде. Это является гарантией стабильного качества работы ПО.

    Микросервисная архитектура позволяет легко переконфигурировать и усовершенствовать ПО

    Для больших приложений корпоративного масштаба использование микросервисной архитектуры – оптимальное решение, позволяющее быстро реагировать на изменение рынка.

    Внедрение микросервисов дает следующие преимущества бизнесу:

    • оперативное расширение и совершенствование функций без затрагивания других микросервисов;
    • тестирование новых функций без затрагивания рабочих – это возможно благодаря замене или добавлению микросервисов в систему;
    • безопасное внедрение инноваций;
    • взаимозаменяемость модулей;
    • готовность к горизонтальному и вертикальному масштабированию;
    • возможность распределения;
    • бесперебойная работа всех компонентов и системы в целом даже при отказе ряда микросервисов;
    • централизованное внесение изменений.

    Использование микросервисной архитектуры оправдано, если какой-либо функционал приложения переиспользуется. Такой подход даст необходимую гибкость, мобильность и масштабируемость бизнесу.

    Наша компания исследует ваш бизнес и предложит оптимальный вариант разработки программного обеспечения. Специалисты HHI быстро и качественно проведут тестирование и внедрение.

    Пара слов в защиту монолита

    Сравниваем особенности микросервисной и монолитной архитектуры, их преимущества и недостатки. Статья подготовлена для Хабра по материалам нашего митапа Hot Backend, который прошел в Самаре 9 февраля 2020 года. Мы рассматриваем факторы выбора архитектуры в зависимости от конкретной задачи.

    Еще лет 5 назад никто и не слышал о микросервисах. Однако, их популярность увеличивается из года в год, согласно статистике Google Trends.

    Монолит и микросервисы: примеры

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

    Микросервисная архитектура предполагает разбивку на модули, которые запускаются как отдельные процессы и могут иметь отдельные серверы. Каждый микросервис работает со своей базой данных, и все эти сервисы могут общаться между собой как синхронно (http), так и асинхронно. При этом для оптимизации архитектуры желательно минимизировать взаимосвязи между сервисами.

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

    Микросервисы: преимущества

    Можно выделить как минимум четыре плюса микросервисной архитектуры:

    Независимое масштабирование и развертывание

    Для каждого микросервиса предусмотрен независимый деплой, и это удобно при обновлении отдельных модулей. Если нагрузка на модуль возрастает, соответствующий микросервис можно масштабировать, не затрагивая остальные. Это позволяет гибко распределять нагрузку и экономить ресурсы.

    Каждый микросервис (например, модуль памяти) можно разработать силами одной команды, чтобы увеличить скорость создания программного продукта.

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

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

    В среде разработчиков можно услышать мнение, что монолитная архитектура устарела, ее сложно сопровождать и масштабировать, она быстро разрастается в “большой ком грязи” и практически является антипаттерном, то есть ее наличие в коде нежелательно. В качестве доказательства этого мнения зачастую приводятся крупные компании, например, Netflix, которые перешли на микросервисную архитектуру в своих проектах.

    Давайте разберемся, действительно ли всем следует переходить от монолита к микросервисам по примеру крупнейших брендов?

    Переход на микросервисы: возможные затруднения

    Проблема первая: декомпозиция

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

    Если возникает необходимость перенести часть функций из сервиса А в сервис Б, то здесь возможны затруднения: например, сервисы выполнены на разных языках, внутренние вызовы сервисов становятся сетевыми, нужно подключать другие библиотеки. Проверить правильность рефакторинга мы можем только с помощью тестов.

    Проблема вторая: транзакции

    Еще одна проблема связана с тем, что у микросервисов нет понятия распределенных транзакций. Мы можем гарантировать архитектурную целостность бизнес-операции только в рамках одного микросервиса. Если операция затрагивает несколько микросервисов, там могут быть использованы разные базы данных, и от такой транзакции придется отказаться. Для решения этой проблемы есть разные методы, используемые в бизнесе, когда доступность оказывается важнее, чем целостность. При этом предусматривают компенсирующие механизмы на случай, если что-то пойдет не так. Например, если товара нет на складе, нужно осуществить возврат денег на счет покупателя.

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

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

    Проблема третья: построение отчетов

    Если мы используем монолитную архитектуру с единой базой данных, для построения сложного отчета можно написать select и подтянуть несколько табличек с данными: рано или поздно они будут выведены. Однако, на микросервисах эти данные могут быть раскиданы по разным базам.

    Например, нам нужно вывести список компаний с определенными метриками. При выводе простого списка компаний все работает. А если нужно добавить метрики, которые лежат в другой базе данных? Да, мы можем сделать дополнительный запрос и по ИНН запросить метрики. А если этот список нужно фильтровать и сортировать? Список компаний может оказаться очень большим, и тогда нам приходится вводить дополнительный сервис со своей базой данных — отчеты.

    Проблема четвертая: высокая сложность разработки

    Работа над распределенными сервисами сложнее: все запросы осуществляются по сети и могут «заглючить», нужно предусмотреть callback механизм (будет ли он осуществлять вызов повторно? Сколько раз?). Это «кирпичики», которые постепенно накапливаются и вносят свой вклад в увеличение сложности проекта.

    Сервисы могут быть разработаны несколькими разными командами, и нужно документировать их, поддерживать документацию в актуальном состоянии, предупреждать другие команды при смене версии. Это дополнительные трудозатраты.

    Если у каждой команды независимый деплой, нужно поддерживать как минимум предыдущую версию и отключать ее только после того, как все потребители сервиса перейдут на новое API.
    Конечно, мы можем вынести все API в некий артефакт, который будет общедоступен. Но, во-первых, сервисы могут быть написаны на разных языках, во-вторых, так делать не рекомендуется. Например, в одном из наших проектов мы отказались от этого по желанию заказчика, связанному с соображениями безопасности. Каждый микросервис имеет отдельный репозиторий, причем заказчик не дает доступ к ним.

    В процессе разработки все может работать корректно, а потом – нет. Бывает, что в случае возникновения исключений приложение бесконечно пытается их обработать, и это дает большую нагрузку – вся система «ложится». Чтобы избежать таких ситуаций, нужно все настроить, например, ограничить количество попыток, не возвращать это обращение в очередь в ту же секунду и т.д.

    Проблема пятая: сложность тестирования, трассировки и отладки

    Чтобы протестировать какую-либо проблему, нужно скачать все задействованные микросервисы. Отладка становится нетривиальной задачей, а все логи нужно собирать где-то в одном месте. При этом логов нужно как можно больше, чтобы разобраться, что случилось. Для отслеживания проблемы нужно понять весь путь, который прошло сообщение. Юнит-тестов здесь недостаточно, поскольку вероятны ошибки на стыке сервисов. При внесении изменений убедиться в работоспособности можно только после прогона на стенде. Мы можем ограничить каждый микросервис некоторым объемом памяти (например, 500 мегабайтов), но бывают моменты пиковой нагрузки, когда потребуется до двух гигабайтов. Бывают моменты, когда система начинает тормозить. В результате ресурсы могут расходоваться на то, что не относится к непосредственным задачам клиента: к примеру, есть всего два бизнесовых микросервиса, а половина ресурсов расходуется на три дополнительных микросервиса, поддерживающих работу остальных.

    Микросервис или монолит: критерий выбора

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

    Если предметная область простая, а глобального прибавления количества пользователей не ожидается, то можно без сомнений использовать микросервисы. В остальных случаях лучше начинать разработку на монолите и сэкономить ресурсы, если масштабирование не потребуется. Если предметная область сложная, а на начальном этапе не определены окончательные требования, тоже лучше начинать с монолита – чтобы не переделывать микросервисы по несколько раз. При дальнейшем развитии проекта можно выделить отдельные его части в микросервисы.

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

    У каждого модуля должен быть свой API, чтобы впоследствии его можно было выделить и сделать модуль микросервисом.

    Определив границы модулей, можно переходить к декомпозиции на микросервисы, если это понадобится. Примерно в 90% случаев можно будет остаться на монолите, но при необходимости вам будет легче и дешевле изменить архитектуру.

    В нашей практике работы с монолитом и микросервисами мы пришли к следующим выводам:

    • Не переходите на микросервисы только потому, что их используют Netflix, Twitter, Facebook
    • Начните с двух-трех микросервисов, которые взаимодействуют друг с другом, детально проработайте на них все нефункциональные требования (безопасность, отказоустойчивость, масштабируемость и т.п.) и только потом переходите к остальным сервисам
    • Автоматизируйте все, что только возможно
    • Настройте мониторинг
    • Пишите автотесты
    • Не используйте распределенные транзакции (но это не повод отказаться от гарантии целостности данных).
    • Если вы хотите использовать микросервисную архитектуру, будьте готовы к тому, что разработка может обойтись вам примерно в 3 раза дороже, чем на монолите. Однако, обе технологии имеют свои недостатки и преимущества, у каждой из них есть своя ниша.

    Микросервисы vs монолитная архитектура [закрыто]

    Я немного почитал о микросервисов, и я немного заинтригован.Кажется, это интересная концепция. Но интересно, в чем преимущества и недостатки использования микросервисов над монолитной архитектурой, и наоборот.

    когда микросервисы подходят лучше, и куда лучше идти с монолитной архитектурой.

    3 ответов

    пока я относительно новичок в мире микросервисов, я постараюсь ответить на ваш вопрос как можно более полной.

    когда вы используете архитектуру микросервисов, вы увеличите развязку и разделение проблем. Так как вы litteraly разделение вашего приложения.

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

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

    поскольку различные службы небольшие и развертываются отдельно, это очевидно легче масштабировать их, с тем преимуществом, что вы можете масштабировать конкретные службы вашего приложения (с монолитным вы масштабируете полную «вещь», даже если это просто определенная часть в приложении, которая получает чрезмерную нагрузку).

    однако, для приложений, которые не собирался становиться слишком большим, чтобы управлять им в будущем. Лучше держать его при монолитной архитектуре. Поскольку архитектура микросервисов сопряжена с некоторыми серьезными трудностями. Я заявил, что проще развернуть микросервисы, но это справедливо только по сравнению с большими монолитами. С помощью микросервисов у вас есть дополнительная сложность распространения услуг на разных серверах в разных местах, и вам нужно найти способ управлять всем этим. Здание микрослужб будет поможет вам в долгосрочной перспективе, если ваше приложение станет большим, но для небольших приложений просто проще оставаться монолитным.

    Это очень важный вопрос, потому что несколько человек заманивают весь шум вокруг микросервисов, и есть компромиссы, чтобы рассмотреть. Итак, каковы преимущества и проблемы микросервисов (по сравнению с монолитной моделью)?

    преимущества

    • Развертываемости: больше гибкости для развертывания новых версий службы из-за более коротких циклов сборки+тестирования+развертывания. Кроме того, гибкость в использовании службы безопасности, репликации, персистентность и конфигурации мониторинга.
    • надежность: неисправность конструирование поражает, что конструирование в покое и ее потребителей, тогда как в монолитном модели неисправности сервис может обрушить всю монолита.
    • в наличии: развертывание новой версии микросервиса требует небольшого времени простоя, в то время как развертывание новой версии сервиса в монолите требует обычно более медленного перезапуска всего монолит.
    • масштабируемость: каждый микросервис можно масштабировать независимо с помощью пулов, кластеров, сеток. Характеристики развертывания делают микросервисы отличным соответствием эластичности облака.
    • Модифицируемости: больше гибкости для использования новых фреймворков, библиотек, источников данных и других ресурсов. Также, микросервисы свободн-соединены, модульные компоненты только доступные через их контракты, и следовательно более менее прональны повернуть в большое ком грязи.
    • управления приложение развитие усилия разделены между командами, которые меньше и работают более независимо.
    • дизайн автономии: команда имеет право использовать различные технологии, базы данных и моделей для разработки и реализации каждого микрослужб, и может изменить и перераспределить каждой конструирование независимо

    задачи

    • Развертываемости: существует гораздо больше единиц развертывания, поэтому есть более сложные задания, сценарии, области передачи и файлы конфигурации для наблюдения за развертыванием. (По этой причине, непрерывной доставки и DevOps весьма желательны для проектов конструирование.)
    • производительность: услуги, скорее всего, нужно общаться по сети, в то время как услуги в пределах монолита может принести пользу от местных звонков. (По этой причине дизайн должен избегать «болтливых» микросервисов.)
    • Модифицируемости: изменения в контракте, скорее всего, повлияют на потребителей, развернутых в другом месте, в то время как в монолитной модели потребители, скорее всего, будут находиться внутри монолита и будут развернуты в ногу со службой. Кроме того, механизмы повышения автономности, такие как возможная согласованность и асинхронные вызовы, усложняют Микросервисы.
    • Контролепригодность: интеграционные тесты сложнее настроить и запустить, поскольку они могут охватывать разные микросервисы в разных средах выполнения.
    • управления: попытка управлять операции увеличивается, потому что есть больше компонентов среды выполнения, файлов журнала и взаимодействия точка-точка для наблюдения.
    • использование памяти: несколько классов и библиотек часто реплицируются в каждом комплект конструирование и общий объем памяти увеличивается.
    • во время выполнения автономии: в монолите объединена общая бизнес-логика. С микрослужб логика распространилась по микрослужб. При прочих равных условиях, более вероятно, что микросервисы будут взаимодействовать с другими микросервисами по сети-это взаимодействие уменьшает автономность. Если взаимодействие между микрослужб подразумевает изменение данных, необходимость транзакционные границы дальнейший компромисс автономии. Хорошей новостью является то, что во избежание проблем автономии времени выполнения мы можем использовать такие методы, как возможная согласованность, управляемая событиями архитектура, CQRS, кэш (репликация данных) и выравнивание микросервисов с ограниченными контекстами DDD. Эти методы не присущи микросервисов, но были предложены практически любой автор я читал.

    Как только мы поймем эти компромиссы, есть еще одна вещь, мы должны знать, чтобы ответить другой вопрос: что лучше, микросервисы или монолит? нам нужно знать нефункциональные требования (требования к качеству атрибута) приложения. Как только вы поймете, насколько важна производительность и масштабируемость, например, вы можете взвесить компромиссы и принять обоснованное дизайнерское решение.

    @Luxo находится на месте. Я просто хотел бы предложить небольшое изменение и привести организационную перспективу. Микросервисы не только позволяют отделять приложения, но и могут помочь на организационном уровне. Например, организация могла бы разделиться на несколько групп, каждая из которых могла бы разработать набор микросервисов, которые может предоставить команда.

    например, в крупных магазинах, таких как Amazon, у вас может быть команда персонализации, электронная коммерция команда, команда обслуживаний инфраструктуры, etc. Если вы хотите попасть в микросервисы, Amazon является очень хорошим примером этого. Джефф Безос сделал его мандатом для команд, чтобы общаться с услугами другой команды, если им нужен доступ к общей функциональности. См.здесь для краткого описания.

    кроме того, инженеры из Etsy и Netflix также были небольшие дебаты еще в день микросервисов против монолита в Twitter. Дебаты немного менее технические но также может предложить несколько идей.

    Добавить комментарий