Хабрахабр

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

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

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

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

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

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

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

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

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

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

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

Независимая разработка

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

Устойчивость

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

Разнородность

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Похожие статьи

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

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть