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

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

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

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

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

Другие особенности монолитов

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

  2. Если в одном из компонентов приложения появляются обновления, закатить их можно только если пересобрать приложение целиком;

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

  4. При отладке надо будет искать неисправность в контексте всей кодовой базы приложения;

  5. Если мы захотим масштабировать приложение, нам придется делать это комплексно или переходить на микросервисы.

Монолиты появились раньше микросервисов на 20 лет, и они до сих пор более распространены, чем микросервисы. Я считаю что главные их плюсы — скорость и простота разработки.

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

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

Монолиты — это вариант для большинства Enterprise-продуктов, стартапов (туда же Minimum viable product и Proof of concept) и приложений с тесно связанной бизнес-логикой.

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

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

Идея собрать приложение как конструктор — из сервисов, которые содержат какую-то законченную логику и хранят данные независимо от других сервисов. Для обмена информацией между ними существуют два способа – синхронные (протоколы обмена данными REST-like, gRPC, SOAP) и асинхронные (брокеры сообщений такие как RabbitMQ, ZeroMQ, ActiveMQ или стриминги по типу kafka). Вот хорошая статья с которой можно начать знакомство с этими темами.

Начиная с 2012 года Amazon, Twitter, Netflix и многие другие компании начали частично переходить на микросервисы. Они позволили не только эффективней справляться с растущим трафиком приложений, но и увеличить частоту релизов, ведь каждый сервис может обновляться независимо от остальных.

Проект, над которым я работаю сейчас с командой, – ERP-система для крупной российской компании. Она упрощает документооборот и автоматизирует процессы принятия решений по лизинговым сделкам. Логичное замечание — я только что сказал, что большинство Enterprise-проектов реализуются на монолитах, тогда чем отличается наш проект?

Главные отличия:

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

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

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

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

Модульные монолиты

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

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

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

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

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

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

Так когда точно нужны микросервисы

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

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

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

  4. Когда важно сократить цикл разработки, обеспечить параллельную разработку несколькими командами.

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

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

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

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

Комментарии (10)


  1. leon-mbs
    31.05.2024 16:10
    +1

    а зачем эти крайности?

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


  1. dsh2dsh
    31.05.2024 16:10
    +7

    Монолиты и микросервисы: что выбрать разработчику

    То, что наиболее подходит для текущего проекта. Ваш кэп.


  1. gudvinr
    31.05.2024 16:10
    +2

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

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

    А какие варианты ещё есть, которые не монолиты и не микросервисы, от которых система неэффективная и кодовая база неудобная?


  1. Farongy
    31.05.2024 16:10
    +2

    А ещё есть распределённые монолиты, которые зачастую и пилят...


    1. headliner1985
      31.05.2024 16:10

      Самый худший из возможных вариантов)


  1. ManGegenMann
    31.05.2024 16:10

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

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

    Тем более что микросервисы тоже можно заставить быть такими. Достаточно чтобы у вас была монорепа.


    1. kozlov_de
      31.05.2024 16:10

      Если этому стеку 10+ лет то плохо

      Мы тут режем такое

      Если бы это был .net то можно резать на DLL, каждая на своём фреймворке, стеке. На ПХП придётся резать на отдельные приложения по шаблону service based architecture, общающиеся через rest API, но с единой БД


  1. nin-jin
    31.05.2024 16:10
    +1

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


    1. headliner1985
      31.05.2024 16:10
      +2

      Это называется модульный монолит, который и надо делать в 90% случаев.

      И вообще на западе уже давно разочаровались в микросервисах. Если вы не Твиттер/гугл/фэйсбук вам скорее всего не нужны микросевисы.


  1. SpiderEkb
    31.05.2024 16:10

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

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

    А еще есть LLVM...

    Монолиты — это вариант для большинства Enterprise-продуктов, стартапов (туда же Minimum viable product и Proof of concept) и приложений с тесно связанной бизнес-логикой.

    Очень сомнительное утверждение. Ну разве что "модульные монолиты" (которые и не монолиты вовсе).

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

    А теперь представьте, что БД у вас - десятки тысяч объектов (таблиц, индексов). Терабайты данных. И все эти объекты и данные используются совместно (в основном) всеми сервисами.

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

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

    Аналогично

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

    Аналогично

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

    Аналогично. Высокопроизводительная, высоконагруженная, высоконадежная система. АБС банка из топ-10 с 50млн клиентов.

    можно добиться и другим путём — разделением монолита на модули

    Бинго!

    БД одна - все работают с ней в реальном времени. Система "многопользовательская" - все, что работает (любая программа), работает в рамках своего "задания" (job), которое является своего рода "контейнером" - своя память, свои настройки окружения. Падение (или принудительное закрытие) одного задания никак не влияет на остальные. Программа может быть вызвана как синхронно (в том же задании), так и асинхронно (в отдельном фоновом задании).

    Для обмена данными система предоставляет предостаточно средств - очереди (системные объекты - простые, быстрые), пользовательские пространства, пользовательские индексы и т.п.

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

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

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

    Именно так.

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

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

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

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

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

    Ну не повезло...

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

    Нонсенс. Если у вас из бизнес-процесса выпадает кусок логики, весь процесс становится невалидным.

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

    Точно также реализуется в модельных монолитах.

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

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

    Когда важно сократить цикл разработки, обеспечить параллельную разработку несколькими командами

    Аналогично.