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

Если команда тратит больше времени на согласование релизов и разбор межсервисных сбоев, чем на изменения продукта, разделение системы может окупиться. Но количество пользователей и размер репозитория сами по себе не повод переходить на микросервисы: сначала проверьте, где именно монолит мешает работе и готова ли команда обслуживать распределённую систему.
Что именно вы хотите разделить
Под словом «монолит» часто смешивают две разные вещи. Монолитное приложение собирают и выпускают как единое целое; при этом внутри оно может иметь строгие модули и границы. Микросервисы — отдельные приложения, которые развиваются и развёртываются независимо, а взаимодействуют через сеть или сообщения.
Поэтому первый шаг — не выбирать между «старым» и «современным», а найти границу, где независимость даст измеримую пользу. Например, каталог товаров выпускают несколько раз в неделю, а расчёт платежей меняют редко и тестируют отдельно. Если эти части зависят друг от друга на уровне данных и релиза, извлечение платежей в отдельный сервис может не упростить, а усложнить систему.
Разделяйте не папки в репозитории, а ответственность, которую можно развивать и выпускать независимо.
Граница домена — зона ответственности системы с собственными правилами и понятными связями с остальными частями продукта.1 Это полезнее, чем механически делить приложение по техническим слоям: например, выносить все контроллеры в один сервис, а всю работу с базой — в другой.
Три варианта и их цена
Между единым приложением и десятками сервисов есть промежуточное решение: модульный монолит. Он выпускается целиком, но внутри имеет явные границы модулей и ограниченные зависимости. Это позволяет навести порядок без сетевой инфраструктуры, а при необходимости позже вынести отдельный модуль.
| Вариант | Что получаете | Чем платите | Когда рассматривать |
|---|---|---|---|
| Монолит | Один процесс релиза, простые локальные вызовы, меньше инфраструктуры | Компоненты связаны общей сборкой и часто общим хранилищем | Небольшая команда, продуктовые границы ещё меняются |
| Модульный монолит | Границы и ответственность внутри единого приложения | Нужны правила зависимостей и контроль за их соблюдением | Сложность растёт, но независимость релизов пока не нужна |
| Микросервисы | Отдельные релизы и масштабирование компонентов | Сетевые ошибки, наблюдаемость, интеграционные тесты и эксплуатация | Есть устойчивая граница и команда, способная владеть сервисом целиком |
Признаки, что разделение может помочь
Не полагайтесь на общее ощущение «код стал большим». Запишите конкретные потери за несколько циклов разработки: время ожидания релиза, число откатов, причины инцидентов, объём изменений, которые приходится выпускать вместе. Сравнивайте динамику на одинаковом горизонте и отмечайте размер команды и тип изменений.
- Релизы блокируют друг друга. Команды готовы выпускать изменения независимо, но общий релизный процесс заставляет ждать соседей. Проверьте, действительно ли задержка вызвана сцеплением кода, а не ручным тестированием или редкими окнами выкладки.
- Компоненту нужны отдельные ресурсы. Например, обработка изображений упирается в процессор, а основное приложение — нет. Сначала выясните, можно ли решить проблему настройкой, очередью или масштабированием всего приложения; отдельный сервис добавит стоимость сетевого обмена и эксплуатации.
- Участки системы имеют разные требования к надёжности. Тогда отдельное развёртывание или изоляция отказов могут быть полезны. Но отдельный процесс сам по себе не гарантирует изоляцию: общие база, очередь или лимиты инфраструктуры всё ещё создают общую точку отказа.
- Граница ответственности устойчива. Команда может описать владельца компонента, его входы, выходы и данные, не ссылаясь на внутренности других частей. Если правила продукта постоянно требуют совместных изменений, границу, вероятно, выбрали рано или не там.
Когда сначала укрепить монолит
Оставаться на монолите — не значит игнорировать архитектуру. Если изменения одной области регулярно ломают другую, отделите модули внутри приложения: определите владельцев данных, запретите прямые зависимости между модулями и оставьте взаимодействие через ограниченные интерфейсы. Для этого не нужно заранее создавать сетевой API.
Микросервисы почти наверняка добавят работу, если команда небольшая, релизы редки, границы продукта неясны или нет средств наблюдать за запросом через несколько компонентов. У отдельного сервиса появятся собственный запуск, конфигурация, мониторинг, обработка сбоев и проверка совместимости. Если всё это должен поддерживать один и тот же разработчик без автоматизации, независимость на схеме может обернуться дополнительным дежурством.
Особенно осторожно разделяйте части, которые должны менять данные в одной бизнес-операции. В монолите это часто решается одной транзакцией базы данных. Между сервисами такая гарантия не переносится автоматически: придётся проектировать повторы, компенсацию частично выполненных действий и поведение при временной недоступности соседей.
Как проверить решение до большого переезда
- Сформулируйте проблему одним предложением. Например: «изменения в расчёте доставки задерживают релизы каталога». Если вместо конкретного эффекта получается «архитектура неудобная», соберите данные о задержках и сбоях.
- Найдите кандидата на границу. Опишите его ответственность, владельца, входящие запросы и данные, которыми он должен управлять. Если несколько команд по-разному отвечают на вопрос, кому принадлежат данные, сначала уточните правила домена.
- Проверьте связи и совместные изменения. Посмотрите историю изменений и зависимости за выбранный период. Сколько раз предполагаемый компонент менялся одновременно с соседним? В каких сценариях им нужна единая транзакция? Не подменяйте наблюдение впечатлением.
- Сравните стоимость двух вариантов. Для модульного монолита оцените работу по границам и тестам; для сервиса — дополнительно развёртывание, мониторинг, сетевые сбои, поддержку контрактов и дежурства. Учитывайте не только стартовую миграцию, но и постоянную эксплуатацию.
- Проведите ограниченный пилот. Выберите компонент с ясной ответственностью и небольшим числом связей. До переноса зафиксируйте текущие показатели: частоту релизов, время восстановления после сбоя и долю изменений, затрагивающих соседние части. После пилота сравните те же показатели и отдельно посчитайте новую операционную работу.
Если после пилота релизы стали независимыми, а время диагностики и поддержки не выросло сверх приемлемого для команды уровня, направление может быть оправдано. Если появились сетевые ошибки, но исходная задержка релизов никуда не делась, остановитесь: возможно, проблема была в процессе или граница оказалась неверной.
Что ломается после разделения
Самая частая ловушка — распределённый монолит: компоненты разнесли по процессам, но каждое изменение всё равно требует синхронного обновления нескольких сервисов. Система получает сетевые задержки и отдельные отказы, а независимости релизов не получает.
- Общая база без правил владения. Несколько сервисов напрямую меняют одни таблицы. Схему трудно менять независимо, а ошибка одного компонента затрагивает остальные.
- Синхронная цепочка вызовов. Запрос проходит через несколько сервисов. Временный сбой одного из них может замедлить весь сценарий, если не предусмотрены тайм-ауты и ограничение повторов.
- Нет сквозной диагностики. В логах одного сервиса виден только локальный сбой, а путь запроса теряется. До выделения сервиса обеспечьте возможность связывать события одного запроса в разных компонентах.
- Слишком мелкие сервисы. Команда тратит время на взаимодействие и обслуживание границ, а не на отдельную ответственность. Размер сервиса не главный критерий — важнее независимость его изменений.
Когда что выбирать
Оставьте монолит, если продукт и команда пока меняются быстрее, чем устоялись границы. Выбирайте модульный монолит, если нужно снизить связанность, но нет доказанной выгоды от отдельных релизов. Выносите сервис, когда у компонента есть устойчивый владелец, понятная ответственность и измеримая причина для независимого развёртывания или масштабирования.
Универсального порога по числу разработчиков, запросов в секунду или размеру кода нет. Решение зависит от профиля нагрузки, устройства данных, навыков команды и цены отказа. Смотрите на показатели до и после, а не на то, сколько сервисов появилось на диаграмме.
1 В контексте предметной области граница ответственности описывает, какие правила и данные принадлежат одному компоненту. Её конкретное название и строгое определение могут различаться в разных архитектурных подходах.
Что делать дальше
Выберите одну проблему, которую хотите устранить, и соберите базовые показатели за несколько циклов релиза. Затем попробуйте оформить границы модулей внутри монолита и проверьте, какие изменения всё ещё требуют совместного выпуска. Только после этого оценивайте пилот с отдельным сервисом; в проде отслеживайте время релиза, частоту откатов, время восстановления и число сценариев, зависящих от нескольких компонентов.
Автоэксперт / механик: Расшифровка OBD2-кодов, выбор б/у авто, диагностика по симптомам.
Спросить за 12 ₽Источники: Microservices — Martin Fowler
Частые вопросы
Большой монолит — уже повод переходить на микросервисы?
Можно ли сначала просто разделить приложение на модули?
Как понять, что граница сервиса выбрана правильно?
Микросервисы помогут, если один участок приложения медленный?
Нужно ли разбивать общую базу при переходе?
Как измерить, окупилось ли разделение?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.