Разработка 6 июля 2026 · 10 мин чтения 10 0

Microservices vs Modular monolith: когда что выбирать в 2026

Десять лет назад в индустрии царил консенсус: будущее за микросервисами. Монолиты — устаревшая архитектура, тянущая команду назад. Любой серьёзный проект должен разбиваться на сервисы, каждый со своей зоной ответственности, развёрнутый и масштабируемый независимо. Эту парадигму подкрепляли успешные истории Netflix, Amazon, Spotify — компаний, построивших миллиардный бизнес на микросервисной архитектуре.

К середине 2020-х маятник качнулся в обратную сторону. Накопленный опыт показал: микросервисы — не серебряная пуля. Многие команды, перешедшие на них преждевременно, страдают от сложности эксплуатации, медленной разработки, сложного дебага. Параллельно концепция modular monolith — структурированный монолит с чёткими внутренними границами — стала восприниматься как разумная альтернатива. Разбираем устройство двух подходов, реальные trade-offs, критерии выбора и пути миграции.

Монолит, modular monolith, микросервисы

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

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

Modular monolith — монолит с явно структурированными модулями. Внутри одной кодовой базы — чёткие границы между подсистемами, контракты взаимодействия, изолированные данные. Разворачивается как одно приложение, но архитектурно близок к микросервисам по чистоте границ.

Микросервисы — отдельные сервисы, каждый со своей кодовой базой, базой данных, развёртыванием. Общаются через сетевые API (REST, gRPC) или через события (Kafka, RabbitMQ). Каждый может писаться на своём языке, развиваться своей командой, масштабироваться независимо.

Аспект Классический монолит Modular monolith Микросервисы
Кодовая база Одна Одна со структурой Множество
База данных Общая Изолированные схемы Отдельные базы
Развёртывание Одно приложение Одно приложение Независимые сервисы
Внутренние границы Размытые Чёткие, в коде Сетевые, на уровне процессов
Сложность эксплуатации Низкая Низкая Высокая

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

Микросервисная архитектура решает несколько реальных проблем больших систем, что и обеспечило её популярность.

Независимое масштабирование. Если service A нагружен в 100 раз больше, чем service B, в монолите оба масштабируются вместе. В микросервисах service A можно развернуть в 100 instance, service B — в 5. Это даёт значительную экономию инфраструктуры на больших масштабах.

Независимые релизы. В монолите релиз — это деплой всего приложения целиком. Изменения в service A требуют деплоя всей системы, замедляя разработку. В микросервисах service A релизится независимо от других, без необходимости координации.

Полиглот-стек. Разные сервисы могут использовать разные технологии под свои задачи: высокопроизводительный сервис на Go, ML-модель на Python, веб-фронт на TypeScript. В монолите такая гибкость недоступна.

Изоляция отказов. Падение одного микросервиса не обязательно ломает всю систему. В монолите exception в одном модуле часто валит весь процесс.

Организационная масштабируемость. Закон Конвея: архитектура отражает организационную структуру. Большая компания с десятками команд естественно тяготеет к разделению на сервисы — каждая команда владеет своими.

Сложности микросервисов на практике

За 10+ лет опыта индустрия накопила понимание реальной стоимости микросервисов. Многое не очевидно при первом взгляде, но становится больно при попытке эксплуатировать систему в production.

Сетевая сложность. Каждый вызов между сервисами — сетевой запрос с возможностью failure, latency, rate limiting. Сравнительно простая логика «получить пользователя, его заказы, для каждого заказа загрузить товары» превращается в три сетевых вызова с обработкой ошибок и retry-логикой на каждом уровне.

Distributed transactions. Транзакция, охватывающая несколько сервисов и баз данных, — нетривиальная задача. Подходы вроде Saga или 2PC требуют тщательной реализации и обработки edge cases. В монолите это была одна database transaction.

Distributed debugging. Найти источник проблемы, проходящей через 10 сервисов — задача отдельной сложности. Требуется distributed tracing, корреляция логов между сервисами, понимание того, что произошло во время одного запроса в системе.

Версионирование API. Микросервисы общаются через API; изменение API одного сервиса требует обновления зависящих сервисов. В монолите эти зависимости проверяются компилятором или статическими анализаторами.

Operational overhead. Каждый сервис нужно мониторить, логировать, оповещать о проблемах, обновлять, бэкапить. Для 50 микросервисов это огромный объём операционной работы по сравнению с одним приложением.

Среды разработки. Локальный запуск 30 сервисов на ноутбуке разработчика — нетривиальная задача. Нужны Docker Compose, минификации, моки внешних сервисов, документация по запуску. На монолите всё проще: clone репозитория, install dependencies, run.

Реальная стоимость микросервисов часто скрыта на этапе планирования и проявляется через 1–2 года эксплуатации. Команды, не имеющие опыта работы с распределёнными системами, обычно недооценивают эти затраты в 3–10 раз.

Modular monolith как компромисс

Modular monolith пытается дать архитектурные преимущества микросервисов без операционных затрат. Идея: разделить приложение на модули с чёткими внутренними границами и контрактами, но развернуть как одно приложение.

Каждый модуль в modular monolith имеет: собственное API (публичные классы или функции, используемые другими модулями); собственную модель данных (часто отдельная schema в той же базе); внутреннюю реализацию, скрытую от остальных модулей; контракты на взаимодействие, проверяемые компилятором.

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

При этом сохраняются операционные простоты монолита: один процесс развёртывания, одна база данных (или несколько schema), отсутствие сетевых вызовов между модулями, простой локальный запуск, простая отладка.

Когда выбирать микросервисы

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

  • Большие команды (50+ разработчиков): организационно проще иметь много небольших сервисов, чем один большой монолит
  • Сильно различающиеся требования по нагрузке: когда одни функции получают 1000x больше нагрузки, чем другие, независимое масштабирование критично
  • Полиглот-стек по необходимости: если разные части системы реально требуют разных языков (ML на Python, real-time на Go, веб на Node.js)
  • Готовность инвестировать в инфраструктуру: Kubernetes, observability stack, service mesh, dedicated DevOps команда
  • Доменно-зрелые границы: понимание, где проходят естественные швы между подсистемами, накопленное за годы работы с продуктом

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

Когда modular monolith — оптимальный выбор

Modular monolith подходит большинству проектов в большинстве ситуаций. Несколько сценариев, где он явно предпочтителен.

  • Маленькие и средние команды (до 30–50 разработчиков): сложность микросервисов не оправдана выигрышем
  • Стартапы и MVP: главное — скорость разработки и итерации, а не масштабирование инфраструктуры
  • Неопределённые границы предметной области: когда непонятно, как именно разбить систему на сервисы, лучше делать это лениво через модули монолита
  • Ограниченные DevOps-ресурсы: когда нет команды, способной поддерживать сложную инфраструктуру
  • Транзакционно-критичные системы: финансовые операции, где distributed transactions создадут больше боли, чем дадут пользы

Подходы к организации modular monolith

Несколько практик для построения качественного modular monolith.

Domain-driven design (DDD). Подход к структурированию системы по бизнес-доменам. Каждый bounded context становится модулем со своей моделью данных и языком. Этот подход обеспечивает естественные границы, отражающие реальную предметную область.

Hexagonal architecture (ports and adapters). Каждый модуль имеет чёткий «порт» (интерфейс взаимодействия) и «адаптеры» для конкретных реализаций (БД, внешние API). Внутренняя бизнес-логика изолирована от инфраструктурных деталей.

Vertical slices. Альтернатива horizontal layering. Вместо разделения на «контроллеры/сервисы/репозитории», система делится на vertical slices по функциям: каждый slice содержит всё необходимое для одной feature от входной точки до базы данных.

Schema per module. Внутри одной базы данных каждый модуль имеет свою schema, и другие модули не имеют права читать чужие таблицы напрямую. Доступ к данным другого модуля — только через его API.

Практика Что обеспечивает
Bounded contexts (DDD) Естественные границы по бизнес-доменам
Ports and adapters Изоляция бизнес-логики от инфраструктуры
Vertical slices Cohesive структура по feature
Schema per module Изоляция данных без отдельных баз
Module-level APIs Контролируемая зависимость между модулями

Миграция от монолита к микросервисам

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

Strangler fig pattern — самый распространённый паттерн миграции. Постепенное «обрастание» монолита микросервисами: новые функции выносятся в отдельные сервисы, старые продолжают жить в монолите. Со временем монолит «иссыхает», заменяясь набором сервисов.

Modular monolith с чёткими границами делает этот процесс намного проще: модуль уже имеет своё API, изолированные данные, чёткую зону ответственности. «Выселить» такой модуль в отдельный сервис — задача дней-недель. В классическом монолите без модульной структуры миграция модуля может занять месяцы из-за необходимости распутывать переплетение зависимостей.

Главное правило миграции: не делать «big bang» переход. Никогда не пытайтесь переписать монолит на микросервисы за один проект. Это почти всегда заканчивается провалом или многолетней разработкой без production-релиза. Постепенный strangler fig — единственный надёжный путь.

Distributed monolith: антипаттерн

Часто встречающаяся ошибка — миграция в микросервисы без правильного проектирования границ. Результат — distributed monolith: набор «микросервисов», которые тесно связаны друг с другом, не могут развёртываться независимо, требуют синхронных изменений.

Признаки distributed monolith: изменение в одном сервисе требует обновления нескольких других одновременно; нельзя развернуть один сервис без другого; общие базы данных или таблицы между сервисами; цепочки синхронных вызовов между 5+ сервисами для одной операции; «общие» библиотеки с бизнес-логикой, изменения в которых требуют обновления всех сервисов.

Distributed monolith — худший из обоих миров: сложность микросервисов без их преимуществ. Это часто результат преждевременной или неправильной миграции с монолита. Правильное решение — либо вернуться к модульной монолитной архитектуре, либо доработать границы между сервисами до настоящей независимости.

Стоимость инфраструктуры

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

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

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

Микросервисы требуют: Kubernetes-кластер или аналог (управление десятками сервисов), service mesh (Istio, Linkerd) для коммуникации между сервисами, full observability stack (Prometheus, Grafana, Jaeger, ELK), CI/CD для каждого сервиса, secret management (Vault), API gateway, потенциально brokers (Kafka, RabbitMQ).

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

Часто задаваемые вопросы

Стоит ли стартапу начинать с микросервисов?

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

Что такое макросервисы и чем они отличаются от микросервисов?

Макросервисы (часто называемые «services» без «micro») — более крупные сервисы, объединяющие несколько связанных функций в одну единицу развёртывания. Это компромисс: меньше сервисов, чем в чистой микросервисной архитектуре, но больше изоляции, чем в монолите. Многие команды, разочаровавшиеся в чрезмерной фрагментации микросервисов, мигрируют к макросервисам как к более устойчивому подходу.

Можно ли в modular monolith использовать события (event-driven)?

Да, в monolithic event-driven системы существуют и работают. Внутренние события публикуются и обрабатываются в рамках одного процесса, без сетевых вызовов. Это даёт преимущества событийной архитектуры (loose coupling, асинхронность) без сложности распределённого брокера. Хороший подход для систем с явной асинхронной природой логики.

Как организовать команды для modular monolith?

Аналогично микросервисам. Каждая команда отвечает за свои модули, имеет права на изменение их кода, на ревью изменений в их публичных API. Кросс-командные изменения проходят через ревью владельцев модулей. Это даёт organizational ownership без операционной сложности отдельных deployment-юнитов.

Что делать, если уже есть микросервисы, но они работают как distributed monolith?

Несколько путей. Объединить тесно связанные сервисы обратно в один (consolidation). Перепроектировать границы по DDD, выделяя bounded contexts. Доработать API сервисов для устранения избыточных синхронных вызовов. Иногда правильный путь — вернуться к modular monolith через объединение всех сервисов в один с чёткой внутренней структурой.

Какие технологии помогают организовать modular monolith?

В разных языках есть свои инструменты. Java — Spring Modulith явно поддерживает модульную структуру. .NET — Modular Monolith шаблоны и архитектуры. Node.js — NestJS с явной модульной системой. Python — менее формализованно, обычно через дисциплину команды и линтеры на импорты. Главное не технология, а consistent применение принципов.

Заключение

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

Решение между микросервисами и monolith (modular или классическим) должно базироваться на конкретных потребностях: размер команды, требования к масштабированию, доменная зрелость, возможности инфраструктуры. Универсального ответа нет; есть критерии, по которым каждая команда должна принять своё решение.

Главное практическое наблюдение последних лет: компании, начавшие с modular monolith и постепенно мигрирующие к микросервисам по реальной необходимости, обычно опережают тех, кто начал с микросервисов «по дефолту». Поступательный подход даёт лучшее понимание системы, более правильные границы между сервисами, меньше технического долга. Это редкий случай, когда более простой подход на старте даёт лучшие результаты и в долгосрочной перспективе.