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

в 12:53, , рубрики: Анализ и проектирование систем, архитектура, Блог компании SimbirSoft, микросервисы, монолит, Проектирование и рефакторинг

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Автор: SSul

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js