Микросервисы vs монолит: когда стоит разбивать приложение и как не усложнить архитектуру

Микросервисы vs монолит: когда стоит разбивать приложение и как не усложнить архитектуру

Представьте: стартап за год вырастает в 50 раз. Команда из пяти человек превращается в сто. Одно приложение — в десятки сервисов. Деплой, который занимал минуты, теперь требует часов. Простая фича затрагивает семь команд. Никто не понимает, как работает система целиком.

Знакомая история? Это классический сценарий преждевременной микросервисизации. Компания решила "делать как Netflix", не учитывая масштаб и контекст.

Обратная ситуация: монолит на миллион строк кода. Один деплой — два часа. Малейшее изменение ломает неожиданные части системы. Новый разработчик разбирается месяц. Команда из 30 человек постоянно мешает друг другу.

В обоих случаях проблема не в архитектуре как таковой. Проблема — в неправильном выборе для конкретной ситуации.

Эта статья — практический гайд по выбору архитектуры. Без религиозных войн, без "правильного пути". Только критерии, паттерны и реальный опыт команд, которые прошли через оба подхода.

1. Что такое монолит и микросервисы простыми словами

Монолит — это приложение, где весь код собран в одном проекте. Один репозиторий, одна база данных, одна сборка, один деплой. Всё работает в едином процессе.

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

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

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

Ключевые отличия:

ХарактеристикаМонолитМикросервисы
Кодовая базаЕдинаяМножество репозиториев
База данныхОбщаяУ каждого сервиса своя
ДеплойВсё приложение целикомКаждый сервис отдельно
МасштабированиеВсё приложениеОтдельные сервисы
КоммуникацияВызовы функцийHTTP/gRPC/очереди
СложностьНизкая вначалеВысокая сразу

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

Монолиты часто недооценивают. На самом деле для многих проектов это оптимальное решение.

Стартап на ранней стадии

Вы ищете product-market fit. Гипотезы меняются каждую неделю. Нужна скорость итераций, а не масштабируемость. Микросервисы здесь — лишний оверхед.

Instagram до $1 млрд оценки работал на монолитном Django. Shopify обрабатывал миллионы заказов на Ruby on Rails монолите. Basecamp до сих пор монолит.

Команда до 15-20 человек

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

Понятная предметная область

Если бизнес-логика хорошо понятна и не меняется радикально, монолит проще поддерживать. Всё в одном месте, легко увидеть связи.

Ограниченные ресурсы

Микросервисы требуют инфраструктуры: оркестрацию, мониторинг, распределённое логирование, service mesh. Это стоит денег и времени.

Простые требования к масштабированию

Если нагрузка равномерная, а вертикальное масштабирование (больше CPU/RAM) решает проблемы — монолит достаточен.

«Начните с монолита. Микросервисы — это оптимизация, а преждевременная оптимизация — корень всех зол.» — Мартин Фаулер

3. Когда нужны микросервисы

Микросервисы решают конкретные проблемы. Если этих проблем нет — не нужны и микросервисы.

Команда выросла, координация сложна

У вас 50+ разработчиков. Все лезут в один репозиторий, конфликты слияния постоянны. Деплой требует согласования всех команд. Время идти к микросервисам.

Amazon перешёл на микросервисы, когда команды стали мешать друг другу. Появилось правило "две пиццы" — команда не должна быть больше, чем могут накормить две пиццы (6-10 человек). Каждая команда — свой сервис.

Разная нагрузка на части системы

API поиска получает в 100 раз больше запросов, чем административная панель. Нужно масштабировать их независимо. Монолит придётся масштабировать целиком — дорого и неэффективно.

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

Падение одной функции не должно ронять всю систему. Например, отказ системы рекомендаций не должен ломать оформление заказа.

Разные технологические требования

Часть системы лучше писать на Python (ML-модели), часть — на Go (высоконагруженные API), часть — на Java (корпоративная интеграция). В монолите так не сделаешь.

Независимые циклы разработки

Мобильное API деплоится раз в день, бэк-офис — раз в неделю, платёжный модуль — только после тщательного тестирования. Разные каденции релизов — признак микросервисов.

Регуляторные требования

Платёжный модуль должен соответствовать PCI DSS. Логичнее изолировать его в отдельный сервис, чем сертифицировать весь монолит.

4. Критерии выбора: объективная оценка

Решение не бинарное. Есть спектр между "чистым монолитом" и "полными микросервисами". Вот объективные критерии:

Размер команды

КомандаРекомендацияПочему
1-5 человекМонолитОверхед микросервисов убьёт продуктивность
5-15 человекМонолит с модулямиГотовьтесь к разделению, но не усложняйте
15-50 человекПереходная зонаАнализируйте другие факторы
50+ человекМикросервисыКоординация монолита дороже оверхеда

Масштаб системы

  • До 100K пользователей — монолит справится легко

  • 100K - 1M — монолит с кешированием и оптимизацией

  • 1M - 10M — рассмотрите гибридный подход

  • 10M+ — микросервисы оправданы

Частота деплоев

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

Зрелость DevOps

Микросервисы требуют зрелых практик:

  • CI/CD для десятков репозиториев

  • Оркестрация (Kubernetes)

  • Мониторинг и трейсинг

  • Управление конфигурацией

  • Автоматизация инфраструктуры

Нет этого — микросервисы превратятся в ад.

Бизнес-требования

ТребованиеМонолитМикросервисы
Быстрый выход на рынок
Частые эксперименты
Независимые команды
Высокая доступность
Гибкое масштабирование
Простота поддержки

5. Модульный монолит: золотая середина

Есть третий путь — модульный монолит. Это монолит с чёткими границами внутри. Лучшее из обоих миров.

Что это такое

Код организован в независимые модули. Каждый модуль:

  • Имеет публичный API

  • Скрывает внутреннюю реализацию

  • Не обращается напрямую к данным других модулей

  • Может быть выделен в микросервис при необходимости

Физически это всё ещё монолит — один деплой, одна база. Но логически подготовлен к разделению.

Преимущества

  • Простота разработки — вся система локально, отладка тривиальна

  • Производительность — вызовы между модулями это просто функции

  • Транзакции — ACID работает из коробки

  • Путь к микросервисам — при необходимости модуль легко выделить

Как организовать

Принцип — каждый модуль как будто отдельный сервис:

  • Папка /modules/users — всё про пользователей

  • Папка /modules/orders — всё про заказы

  • Папка /modules/payments — всё про платежи

Модуль Orders не обращается к таблице users напрямую. Только через публичный API модуля Users.

«Начните с модульного монолита. Это даёт гибкость без оверхеда микросервисов. Когда поймёте границы — выделите в сервисы.» — Сэм Ньюман, автор "Building Microservices"

6. Переход от монолита к микросервисам

Если решили мигрировать — делайте постепенно. "Переписать всё с нуля" — рецепт катастрофы.

Этап 1: Заморозьте монолит

Новая функциональность — в новых сервисах. Монолит продолжает работать, но не растёт.

Паттерн Strangler Fig (удушение смоковницы): новые сервисы постепенно заменяют части монолита, как лиана обвивает дерево.

Этап 2: Определите границы

Где провести линии разделения? Критерии:

  • Бизнес-возможности — управление пользователями, обработка заказов, платежи

  • Связанность данных — что меняется вместе, остаётся вместе

  • Команды — каждая команда владеет сервисом

  • Нагрузка — что нужно масштабировать отдельно

Этап 3: Выделите первый сервис

Начните с чего-то периферийного, не критичного. Рекомендации для первого сервиса:

  • Мало связей с другими частями системы

  • Чёткая бизнес-граница

  • Не критична для бизнеса (если упадёт — не катастрофа)

  • Достаточно сложна, чтобы оправдать выделение

Примеры хороших кандидатов: уведомления, отчёты, поиск, интеграции с внешними системами.

Этап 4: Разверните инфраструктуру

До выделения второго сервиса убедитесь, что есть:

  • Автоматический деплой

  • Централизованное логирование

  • Мониторинг и алерты

  • Distributed tracing

  • Service discovery

Этап 5: Итерируйте

Извлеките следующий сервис. Применяйте уроки предыдущего. Через 5-10 сервисов процесс станет рутинным.

Что не делать:

  • ❌ Переписывать всё сразу

  • ❌ Делить без понимания границ

  • ❌ Начинать с критичных модулей

  • ❌ Выделять сервисы без инфраструктуры

  • ❌ Игнорировать существующие данные

7. Паттерны декомпозиции

Как разделить монолит? Есть проверенные стратегии:

По бизнес-возможностям (Business Capability)

Каждый сервис отвечает за законченную бизнес-функцию:

  • User Service — управление пользователями

  • Order Service — обработка заказов

  • Payment Service — платежи

  • Inventory Service — склад

  • Notification Service — уведомления

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

По поддоменам (Subdomain, DDD)

Используйте Domain-Driven Design. Определите:

  • Core Domain — основная ценность бизнеса

  • Supporting Subdomains — вспомогательные функции

  • Generic Subdomains — общие функции (аутентификация, логирование)

Каждый поддомен — потенциальный сервис.

По команде (Team-based)

Обратный закон Конвея: организация системы под структуру команд.

Если есть команда iOS, команда Android, команда Web — создайте API Gateway для каждой. Backend-for-Frontend (BFF) паттерн.

По типу нагрузки (Scalability)

Выделите части с разной нагрузкой:

  • Read-heavy — поиск, каталог

  • Write-heavy — аналитика, логи

  • Compute-heavy — обработка изображений, ML

Каждый тип нагрузки масштабируется по-своему.

ПаттернКогда использоватьСложность
Business CapabilityЧёткие бизнес-границыСредняя
Subdomain (DDD)Сложная предметная областьВысокая
Team-basedАвтономные командыНизкая
ScalabilityРазная нагрузкаСредняя

8. Решение главных проблем микросервисов

Микросервисы создают новые проблемы. Вот как их решать:

Проблема 1: Распределённые транзакции

В монолите транзакции тривиальны. В микросервисах нет единой БД.

Решение — Saga паттерн. Вместо одной транзакции — последовательность локальных транзакций с компенсацией:

  1. Order Service создаёт заказ

  2. Payment Service списывает деньги

  3. Inventory Service резервирует товар

  4. Если что-то упало — откатываем через компенсирующие действия

Проблема 2: Согласованность данных

Каждый сервис хранит свои данные. Как синхронизировать?

Решение — Event-driven архитектура:

  • Сервисы публикуют события: "OrderCreated", "PaymentProcessed"

  • Другие сервисы подписываются на нужные события

  • Eventual consistency — данные согласуются, но не мгновенно

Проблема 3: Сетевая латентность

Вызов функции в монолите — наносекунды. HTTP-запрос между сервисами — миллисекунды.

Решения:

  • Кеширование агрессивное

  • Асинхронная коммуникация (очереди)

  • Правильные границы (минимизировать межсервисные вызовы)

  • GraphQL для агрегации данных

Проблема 4: Отладка и мониторинг

Один запрос проходит через пять сервисов. Где ошибка?

Решение — Observability stack:

  • Distributed Tracing (Jaeger, Zipkin) — трейсы запросов

  • Централизованное логирование (ELK, Loki) — все логи в одном месте

  • Метрики (Prometheus, Grafana) — здоровье сервисов

  • Service mesh (Istio, Linkerd) — прозрачная инфраструктура

Проблема 5: Версионирование API

Нельзя обновить все сервисы одновременно. Нужна обратная совместимость.

Решения:

  • Версионирование в URL: /api/v1/users, /api/v2/users

  • Поддержка старых версий минимум 6 месяцев

  • Мягкая миграция: новое поле опциональное, старое deprecated

9. Инструменты и технологии

Оркестрация

ИнструментПлюсыКогда использовать
KubernetesИндустриальный стандарт, огромная экосистемаСредние и крупные проекты
Docker SwarmПростота, встроен в DockerМалые проекты, быстрый старт
NomadЛегковесность, не только контейнерыГетерогенная инфраструктура

Service mesh

  • Istio — полнофункциональный, сложный

  • Linkerd — легковесный, простой

  • Consul Connect — интеграция с Consul

Service mesh даёт: mTLS, circuit breaking, ретраи, канарейные деплои, трейсинг.

API Gateway

  • Kong — мощный, плагины, open source

  • Tyk — быстрый, GraphQL

  • AWS API Gateway — managed, интеграция с AWS

  • Nginx/Traefik — легковесные варианты

Messaging

ИнструментПаттернКогда использовать
RabbitMQОчереди, маршрутизацияСложная маршрутизация
Apache KafkaEvent streamingВысокая пропускная способность
AWS SQS/SNSManaged очередиAWS инфраструктура
NATSPub/SubЛегковесные задачи

Мониторинг и трейсинг

  • Prometheus + Grafana — метрики и дашборды

  • ELK Stack (Elasticsearch, Logstash, Kibana) — логи

  • Jaeger / Zipkin — distributed tracing

  • Datadog / New Relic — managed полный стек

10. Типичные ошибки

Ошибка 1: Преждевременное разделение

Команда из пяти человек делает микросервисы "чтобы было как у Netflix". Результат: тратят 70% времени на инфраструктуру, 30% на продукт.

Правило: не делайте микросервисы, пока не почувствуете боль от монолита.

Ошибка 2: Распределённый монолит

Разделили на 20 сервисов, но они плотно связаны. Деплой одного требует деплоя всех. Это худшее из обоих миров.

Признаки:

  • Изменение в одном сервисе всегда требует изменений в других

  • Невозможно задеплоить сервис независимо

  • Общая база данных между сервисами

Ошибка 3: Слишком мелкое дробление

Сервис из 100 строк кода — это не сервис, это функция. Оверхед не оправдан.

Правило: сервис должен быть достаточно большим, чтобы оправдать операционный оверхед.

Ошибка 4: Игнорирование операционной сложности

Разработали 30 сервисов, а мониторинга нет. Когда что-то ломается — не понятно где.

Правило: инфраструктура раньше, чем второй микросервис.

Ошибка 5: Синхронные вызовы везде

Все сервисы общаются через REST. Цепочка из 10 последовательных вызовов. Латентность космическая, надёжность нулевая.

Решение: асинхронная коммуникация через события для некритичных операций.

Ошибка 6: Отсутствие API-контрактов

Сервисы меняют API без версионирования. Всё постоянно ломается.

Решение: OpenAPI спецификации, контрактное тестирование, versioning.

11. Чек-лист принятия решения

Оставайтесь с монолитом, если:

  • ☑ Команда меньше 10-15 человек

  • ☑ Продукт на ранней стадии, много экспериментов

  • ☑ Нет проблем с масштабированием

  • ☑ Время выхода на рынок критично

  • ☑ DevOps практики не зрелые

  • ☑ Вся команда находится в одном месте

  • ☑ Бюджет на инфраструктуру ограничен

Переходите к микросервисам, если:

  • ☑ Команда 30+ человек, конфликты в коде

  • ☑ Части системы нужно масштабировать по-разному

  • ☑ Разные команды хотят независимости

  • ☑ Деплой монолита стал медленным и рискованным

  • ☑ Есть зрелые DevOps практики

  • ☑ Можете выделить ресурсы на инфраструктуру

  • ☑ Критична высокая доступность отдельных функций

Выберите модульный монолит, если:

  • ☑ Команда 10-20 человек

  • ☑ Хотите гибкости в будущем

  • ☑ Границы системы не до конца ясны

  • ☑ Нужны преимущества обеих архитектур

Красные флаги (когда точно НЕ делать микросервисы):

  • 🚩 "Так делают в Google/Netflix/Amazon"

  • 🚩 "Хочу попробовать новую технологию"

  • 🚩 "Монолиты устарели"

  • 🚩 Нет понимания, где проводить границы

  • 🚩 Нет специалистов по микросервисам в команде

  • 🚩 Нет инфраструктуры для мониторинга

12. Пошаговый план

Для новых проектов:

  1. Начните с монолита

  2. Организуйте код в модули с чёткими границами

  3. Используйте DDD для определения bounded contexts

  4. Каждый модуль имеет публичный API

  5. Когда команда вырастет или появятся проблемы — выделяйте сервисы

Для существующих монолитов:

  1. Оцените, действительно ли нужны микросервисы

  2. Начните с рефакторинга в модульный монолит

  3. Определите границы через DDD

  4. Выделите первый некритичный сервис

  5. Постройте инфраструктуру

  6. Выделяйте остальные постепенно

  7. Не пытайтесь мигрировать всё

Для существующих микросервисов:

  1. Аудит: какие сервисы слишком связаны?

  2. Объедините то, что часто меняется вместе

  3. Убедитесь в правильности границ

  4. Инвестируйте в мониторинг и трейсинг

  5. Документируйте API и зависимости

13. Что запомнить

Микросервисы — не цель, а средство решения конкретных проблем. Если проблем нет — не нужны и микросервисы.

Ключевые принципы:

  • Контекст решает. Нет универсального ответа. Netflix нужны микросервисы. Вашему стартапу — вряд ли.

  • Начинайте просто. Монолит → модульный монолит → микросервисы. Это эволюция, не революция.

  • Инфраструктура критична. Без зрелого DevOps микросервисы убьют продуктивность.

  • Границы важнее технологий. Неправильно разделённые микросервисы хуже монолита.

  • Измеряйте боль. Переходите к микросервисам, когда боль от монолита превышает оверхед микросервисов.

«Если не можете построить хорошо структурированный монолит, что заставляет вас думать, что микросервисы помогут?» — Саймон Браун, автор "Software Architecture for Developers"

Практические советы:

  • Монолит — не грязное слово. Shopify, GitHub, Basecamp успешны с монолитами.

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

  • Модульный монолит даёт 80% преимуществ без 80% сложности.

  • Если решили мигрировать — делайте постепенно. Strangler Fig, не Big Bang.

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

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

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

А лучшие вакансии для разработчиков ищите на hirehi.ru