Наверное, ни для кого из мира IT не секрет, что микросервисы сейчас очень популярны. В этой статье я предлагаю разобраться, что же они из себя представляют, какими плюсами и минусами обладают в сравнении с монолитными решениями и когда действительно следует их использовать.
Монолитная архитектура
В сущности, это классическая модель построения программного обеспечения, представляющая собой независимый единый модуль, включающий все три архитектурных слоя: данных, доменной логики и представления.
Приложения, построенные по такой архитектуре как правило достаточно увесистые и инерционные. Они основаны на единой кодовой базе, решающей сразу все требуемые бизнес-задачи. Для хранения и синхронизации изменений монолитов используется единый репозиторий.
Монолитные приложения удобны на первых порах проектов, т.к. не требовательны в CI/CD. Благодаря этому, не отвлекаясь на лишние затраты связанные с DevOps можно доставлять клиенту сразу все доработки готовые к выдаче.
Архитектуры такого типа рассчитаны на то, что запросы пользователей будут обслуживаться путем последовательной их обработки на всех уровнях.
Микросервисная архитектура
Архитектура такого типа — это разновидность СОА (service-oriented architecture - SOA), которая основывается на применении, минимальных по размеру, слабосвязанных и легко изменяемых модулей, где в качестве модуля выступает микросервис.
Цитируя Эдриана Кокрофта определение микросервисной архитектуры звучит так: Loosely coupled service oriented architecture with bounded contexts. Что в переводе означает примерно следующее – Архитектура SOA на основе слабо связанных сервисов с ограниченными контекстами.
Это определение заставляет обратить внимание на еще одно свойство – ограниченность контекста, иными словами, каждый микросервис должен отвечать только за какой-то один определенный контекст и не больше (Domain-Driven Design, DDD). Под контекстом здесь понимается какой-то определенный бизнес домен со своим множеством задач, которое в итоге будет имплементировано в рамках по возможности одного микросервиса.
Резюмируя вышесказанное, микросервисная архитектура подразумевает отказ от единой монолитной структуры приложения. Вместо имплементации и исполнения всего множества ограниченных контекстов в одном приложении мы получаем фактически набор приложений, каждое из которых имплементирует и исполняет один конкретный контекст. Благодаря такой разделенности мы получаем относительно легковесные сервисы, которые могут быть развернуты как на одном сервере, так и на внешних и могут быть вызваны как с помощью HTTP, так и с использованием Service Oriented подхода с помощью менеджеров очередей (IBM MQ, RabbitMQ).
Эта модель снискала популярность и начала распространяться в середине 2010-х годов наряду с ростом практик Agile Development и DevOps.
Недостатки
- Требовательность к CI/CD
Использование микросервисов на проекте требует развертывания и конфигурирования причем очень часто довольно специфичного. Кроме того, база сервисов постепенно растет, и чтобы сократить расходы на обслуживание без автоматизации интеграции изменений, тестирования и развертывания не обойтись. Для решения этих задач в команде должны быть DevOps инженеры, а также не обойтись без систем автоматизированного развертывания и оркестрации. Более того, разработчикам также придется тщательно документировать свои сервисы и тесно взаимодействовать с тестировщиками и другими членами команды для передачи знаний и оказании помощи в решении проблем.
- Рассогласованность среди разработчиков
Разное видение нюансов реализации микросервисной архитектуры членами команды совместно с отсутствием предоставления проработанных и утвержденных подходов может приводить к большому количеству синхронизационных митингов и споров, что приводит к деградации продуктивности. Также этому потворствует разница в уровне навыков среди разработчиков.
- Изоляция разработчиков
Ввиду того, что фокус ответственности разработчиков сужается до одного сервиса, они перестают видеть обновления в других и понимать курс развития приложения в целом. Кроме того, переключение на помощь в разработке смежных сервисов как правило затратно, т.к. требует изучения бизнес домена, кодовой базы и текущих проблем (переключения контекста).
- Требовательность к мониторингу
Если на проекте монолитное приложение, то мониторить его состояние при должной организации достаточно легко. Микросервисов могут быть десятки и даже сотни, и в таком случае следить за исправностью каждого трудно, а иногда просто невозможно.
Для решения этой проблемы придется подумать о внедрении системы управления и мониторинга (например open source инструменты Netflix, Dropwizard, Atlassian Compass и т.д.). Если сервисов не так много и бюджет проекта ограничен, то как вариант можно реализовать свои инструменты мониторинга.
- Требовательность к квалификации кадров
Несмотря на то, что идея микросервисов призвана сделать процесс разработки более гибким и быстрым путем разбиения задач на сервисы, на практике без должного управления за частую все только усложняется. Может потребоваться много времени для того, чтобы оптимизировать работу команд и наладить процессы. Если при этом квалификации разработчиков недостаточно, и она сильно скачет между командами, это может приводить к серьезным сбоям поставок продукта и снижении качества, а лиды и архитекторы будут перегружены.
Помимо этого, разработчикам придется иметь дело с несколько большим стэком инструментов и проектировать сервисы самостоятельно с нуля на всех уровнях, а это в свою очередь требует умения реализации архитектуры, безопасности, хостинга, мониторинга и прочего. Не стоит также забывать, что у некоторых сервисов может быть еще и UI часть и тут потребуются либо навыки full-stack, либо ниже, чтобы эффективно коммуницировать с front-end разработчиками для формирования оптимального API.
- Сложность отладки
Монолитные приложения просты в отладке и не требовательны к локальному развертыванию. Как правило для того, чтобы начать отлаживать программный код приложения нужно развернуть его локально или на виртуальной машине, настроить и запустить.
С микросервисами картина более комплексная. Здесь еще может потребоваться реализовать инфраструктуру запуска сервисов локально, эмуляторы сервисов(моки), эмуляторы очередей пересылки сообщений и прочее.
Более того отладку могут затруднить сложные взаимодействия между множеством сервисов.
- Независимость сервисов и общая кодовая база
Независимость микросервисов — это конечно хорошо, но на практике она очень трудно реализуется. Как правило ее удается установить только когда доменная область сервиса настолько мала и сам сервис настолько прост, что он не требует подключения других проектных библиотек. В основном же вместо независимости мы получаем зависимость, которую нужно контроллировать различными средствами, чтобы уменьшить вероятность выхода сервисов из строя. Существует выбор - либо дуплицировать часто использующийся код в каждом сервисе, если он там требуется, либо подключать пакеты с общей кодовой базой и предоставлять в виде зависимостей сервисами. И то и другое — это торг, который несет проблемы актуальности кодовой базы. Если с дупликацией, итак, понятно, что это плохо, то в случае дистрибуции пакетов еще можно побороться за стабильность сервисов и процессов их разработки за счет затрат на версионирование пакетов, упора на тестирование, более тщательное код ревью и использование автоматизированных средств отслеживания состояния пакетов.
Преимущества
- Простота и гибкость развертывания
Есть возможность разворачивать только какие-то целевые модули, не затрагивая при этом остальную часть приложения. Например, требуется развернуть только модуль, отвечающий за вычисление ставки по кредиту, остальные сервисы не будут изменены или развернуты повторно, потому что модуль представляет собой отдельный микросервис.
Если заказчик хочет отключить или удалить из приложения какие-то определенные модули, микросервисная архитектура легко позволит сделать и это. При их удалении или отключении другие сервисы не будут затронуты. С монолитом же такие фокусы не пройдут. Придется вносить изменения в кодовую базу, а затем разворачивать все приложение целиком.
- Независимость
Все приложение в микросервисных архитектурах разбито на отдельные микросервисы, каждый из которых реализует отдельную бизнес-задачу. Благодаря такой изолированности сокращается влияние других команд/частей приложения, и при соответствующей организации процесс разработки идет быстрее.
Более того, это еще дает простоту внесения изменений, т.к. не требуется изменение всего приложения, а также увеличивает покрытие и глубину юнит тестов на ряду с упрощением тестирования в целом.
- Масштабируемость
Масштабируемость в микросервисных архитектурах проще и эффективнее чем в монолитных, поскольку, во-первых, есть возможность масштабировать только отдельные части приложения - микросервисы, подвергающиеся большой нагрузке, т.е. мы получаем гибкое управление нагрузкой. Во-вторых, меньше накладных расходов на железо и его обслуживание, поскольку сервисы легковесные и не нужно разворачивать много копий массивного монолита.
- Устойчивость к сбоям
Если монолит выходит из строя, то это приводит к падению и недоступности всего приложения. Если же микросервис по каким-то причинам упал, то при должном проектировании это не вызывает отказа всего приложения. Достигается это путем мониторинга и автоматизации перезапуска сервисов как реакцию на отказ. К тому же если в инфраструктуре решения предусмотрено масштабирование сервисов на базе балансировщика нагрузки, то вместо отказавшего сервиса в работу включится его копия и пользователь даже не заметит сбоя.
- Гибкость при выборе стека технологий
Микросервисная архитектура позволяет строить распределенные системы, где сервисы могут быть реализованы на разных фреймворках и языках программирования в зависимости от назначения, требований и удобства, а также развертываться на абсолютно разных платформах и общаться между собой каким угодно из стандартизированных способов(HTTP, Rabbit MQ, IBM MQ, процессное взаимодействие). При этом есть возможность организации согласованной работы всех этих сервисов. Это одно из значимых преимуществ таких архитектур.
- Продуктивность команд разработчиков
Благодаря тому что каждый сервис контекстно независим, появляются следующие преимущества. Новым разработчикам проще начать работу и приносить пользу компании, поскольку они фокусируются только на отдельном домене, отвечают только за один микросервис со своим технологическим стэком. Это позволяет значительно сократить расходы на погружение во все приложение и его поддержку, в отличии от монолита. В последствии при должной организации процесса разработки продукта это дает прирост продуктивности.
Заключение
Основные преимущества использования микросервисов, отсутствующие в монолитной архитектуре – это возможность их относительно дешевого и селективного масштабирования, а также гибкость развертывания и устойчивость к сбоям.
Не смотря на широкую распространенность реализаций на базе микросервисной архитектуры все-таки не стоит без оглядки полностью строить ваш проект на ней, т.к. это может очень дорого стоить в плане создания и обслуживания инфраструктуры. Перед этим лучше потратить время на тщательное изучение предметной области, осмысление задачи и на поиск возможных вариантов ее решения. Не исключено, что в результате изысканий вы поймете, что ваши задачи могут быть эффективно решены с помощью монолита в связке с несколькими масштабируемыми микросервисами, или вовсе будет достаточно только монолита.