Расскажем о плюсах и минусах микросервисов, а также выясним, кому подходит технология.

Что такое микросервисная архитектура

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

В сообществе разработчиков программного обеспечения есть скептики, которые не считают микросервисы чем-то новым и называют их всего лишь ребрендингом сервис-ориентированной архитектуры (SOA, service-oriented architecture), получившей распространение в конце двадцатого века. Однако микросервисы и SOA не одно и то же. К SOA относится множество других шаблонов, среди которых: CORBA, web-сервисы, очереди сообщений, ESB. Поэтому микросервисы стоит воспринимать как конкретный подход к SOA, но не единственный.

Микросервисы vs Монолит

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

Например

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

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

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

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

Недостатки такой схемы монолитной архитектуры очевидны:

  1. Избыточность сборок и развертывания

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

  2. Невозможность масштабирования части приложения

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

  3. Увеличение цены сбоя

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

  4. Сложность внедрения новых технологий

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

  5. Организационные сложности

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

  6. Редкость обновлений

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

  7. Сильная зависимость от модели данных

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

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

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

Например

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

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

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

Ключевые преимущества микросервисов по сравнению с монолитами

  1. Простота развертывания

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

  2. Оптимальность масштабирования

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

  3. Устойчивость к сбоям

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

  4. Возможность выбора технологий

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

  5. Небольшие команды разработки

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

  6. Уменьшение дублирования функциональностей

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

  7. Упрощение замены сервисов при необходимости

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

  8. Независимость моделей данных

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

Недостатки микросервисной архитектуры: как с ними справиться

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

Распределенная система

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

Известны несколько путей решения этой проблемы:

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

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

Усложнение процессов и повышение требований к команде

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

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

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

Необходимость поддержания согласованности приложения

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

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

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

Важно

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

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

Чек-лист: кому не обойтись без микросервисов

  1. Большая команда: если у вас работает больше 10 человек, команда растет, все сложнее погружать новичков целиком в предметную область, то микросервисы помогут стандартизировать разработку и упростить командную работу.
  2. Множество взаимодействующих модулей в приложении: если их количество измеряется десятками, однозначно стоит задуматься о микросервисах.
  3. Объемный код: приложение с многомиллионными строками кода со временем все тяжелее поддерживать и развивать как монолит.
  4. Долгое время запуска приложений (полчаса и более): переход на микросервисы позволит устранить вынужденные простои и эффективно использовать время разработчиков.
  5. Различные требования к ресурсам в рамках одного приложения: использование микросервисов идеально в случаях, когда у разных компонентов отличаются требования к ЦП, памяти и так далее.
  6. Для вашего бизнеса критична непрерывная доставка: если необходимо обеспечить своевременный выход обновлений, микросервисы являются предпочтительным вариантом, так как по скорости развертывания они значительно лучше монолитов.
  7. Высокий трафик со склонностью к периодическим всплескам нагрузки: микросервисы отлично сочетаются с автомасштабированием и облачной моделью, которые позволят использовать ресурсы только тогда, когда в них есть необходимость.