Когда микросервисы — плохая идея

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

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

Микросервисы редко проваливаются громко. Обычно всё выглядит прилично: репозитории на месте, Kubernetes крутится, дашборды красивые. Просто фичи почему-то едут в три раза медленнее, чем год назад, а каждый релиз превращается в созвон восьми человек. Это и есть провал — тихий, растянутый на месяцы. Чтобы его не допустить, надо уметь читать симптомы заранее.

Признаки преждевременного дробления

Дробить рано, если про вашу систему верно хотя бы три пункта из этого списка:

  • Предметная область ещё меняется. Раз в месяц вы переосмысливаете, что такое «заказ» или «клиент». Границы сервисов при таких сдвигах приходится двигать вместе с данными.
  • Команда меньше десяти человек. Микросервисы — лекарство от координации людей. Если координироваться не с кем, вы пьёте таблетку от несуществующей болезни.
  • Нет автоматического деплоя. Если один сервис выкатывается руками — двадцать не выкатятся никак.
  • Нет централизованных логов и трассировки. Первый же межсервисный баг будет расследоваться днями.
  • Нагрузка не требует раздельного масштабирования. Тысяча запросов в минуту прекрасно живёт на одном приложении и одной базе.
  • Аргумент за дробление звучит как «так делают в больших компаниях». В больших компаниях делают так, потому что у них двести команд.

Распределённый монолит: как он выглядит

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

СимптомЧто это значит на самом делеКак проверить
«Выкатываем всё вместе по четвергам»у сервисов общий цикл релиза — то есть общий деплой, как у монолитасколько релизов сервиса A прошло без релиза B за последний месяц?
Общая база данных на несколько сервисовсервисы связаны через схему; миграция ломает соседейсколько разных сервисов ходят в таблицу orders?
Общая библиотека с DTO и моделямиизменение одного поля требует пересборки и релиза всехкак часто меняется пакет common и сколько сервисов его тянут?
Каждый пользовательский запрос идёт по цепочке из 5+ сервисовотказ любого звена = отказ всей функцииоткройте трассу типичного запроса и посчитайте сетевые хопы
Задача в спринте почти всегда трогает 2–3 репозиторияграница проведена не по шву предметной областипосчитайте долю задач с кросс-сервисными изменениями
Локально ничего не работает без всей системысервисы не автономны даже в разработкеможет ли новичок запустить один сервис и его тесты?

Типичный распределённый монолит на схеме выглядит так — обратите внимание, что база одна:

           HTTP          HTTP           HTTP
  api-gw ------> orders ------> billing ------> notify
                   |              |              |
                   +--------------+--------------+
                                  |
                          [ одна общая БД ]

  Отказ notify роняет оформление заказа.
  Миграция в БД требует одновременного релиза трёх сервисов.
  Итог: сложность микросервисов, независимость — нулевая.

Организационное условие: закон Конвея

Организации проектируют системы, копирующие структуру их коммуникаций. — Мелвин Конвей, 1967

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

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

Сколько у вас командЧто разумноПочему
Одна (2–8 человек)модульный монолиткоординировать некого; налог на распределённость не окупится
Две-тримонолит плюс один-два вынесенных сервисавыносим только то, у чего есть особая причина: другая нагрузка, другой стек, другой цикл релиза
Четыре и больше, домены разныемикросервисы оправданыболь от координации уже больше, чем боль от сети

Входной билет: что надо иметь до первого сервиса

Микросервисы — это не про код, а про эксплуатацию. Прежде чем резать, убедитесь, что у вас есть:

  • автоматический CI/CD, который выкатывает сервис в прод без ручных шагов и умеет откатывать;
  • инфраструктура как код: новый сервис поднимается по шаблону за часы, а не за недели;
  • централизованные логи, метрики и распределённая трассировка со сквозным correlation-id;
  • алерты и понятный дежурный: кого будят, если упал сервис;
  • контрактные тесты между сервисами — иначе несовместимость вы узнаете от пользователей;
  • договорённость о версионировании API и обратной совместимости.

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

Как это работает: почему общая база убивает независимость

Самая соблазнительная ошибка — разрезать код, но оставить одну базу: «зачем плодить сущности, там же всё связано». Посмотрите, что происходит дальше.

Было:  orders.status = 'paid' | 'shipped'
Стало: orders.state  = 'PAID' | 'SHIPPED'   (переименование + новый формат)

Кто читает таблицу orders напрямую:
  - orders-service   (свой код, знает про миграцию)
  - billing-service  (чужая команда, про миграцию не знает)
  - analytics-jobs   (ночной скрипт, вспомнят через неделю)

Значит:
  1) миграцию нельзя выкатить в одиночку — нужен общий релиз;
  2) откатить сервис отдельно тоже нельзя — схема уже другая;
  3) чтобы не сломать соседей, приходится согласовывать каждый ALTER.

Вывод: общая схема = общий цикл релиза = монолит по сети.

Правило, из которого не бывает исключений: у каждого сервиса своя база (или хотя бы своя схема), и никто, кроме владельца, не ходит в неё напрямую. Данные соседа получают только через его API или через события. Да, это значит дублирование данных и отказ от удобного JOIN. Именно за эту цену покупается право выкатываться в одиночку — а это и есть единственная настоящая выгода микросервисов.

Частые ошибки

  • Резать «на будущее». Система на 5 тысяч запросов в день не нуждается в двенадцати сервисах — она нуждается в понятных модулях.
  • Оставить одну базу. Самый быстрый способ получить распределённый монолит без единой выгоды.
  • Общая shared-библиотека с моделями. Кажется удобством, работает как жёсткая связь: релиз библиотеки становится релизом всей системы.
  • Синхронные цепочки на каждый чих. Если оформление заказа синхронно ждёт сервис уведомлений — упавшая почта уронит продажи.
  • Дробить, не меняя команды. Пока за код отвечают «все», архитектура по закону Конвея сползёт обратно в общий деплой.
  • Считать возврат к монолиту поражением. Слить обратно два сервиса, которые всегда меняются вместе, — не позор, а нормальный инженерный ход.

Итоги

  • Преждевременное дробление даёт распределённый монолит: сложность есть, независимости нет.
  • Главные маркеры: общая база, общий релиз, общая библиотека моделей, кросс-сервисные задачи в каждом спринте.
  • Закон Конвея: у сервиса должна быть команда-владелец, иначе архитектура схлопнется обратно.
  • До первого сервиса нужны CI/CD, IaC, логи, метрики, трассировка, алерты и контрактные тесты.
  • Единственная реальная выгода микросервисов — независимый деплой. Нет её — нет и микросервисов, как бы ни выглядела схема.
Проверьте себя
1. Команда выкатывает все восемь своих сервисов одним общим релизом, иначе система не работает. Как называется то, что у них получилось?
AМодульный монолит
BРаспределённый монолит
CСервис-ориентированная архитектура
DМикросервисы с оркестрацией
2. О чём говорит закон Конвея применительно к микросервисам?
AАрхитектура системы повторяет структуру коммуникаций в организации
BЧем больше сервисов, тем выше общая надёжность системы
CЛюбую систему можно разрезать на микросервисы без потери качества
DЧисло сервисов должно совпадать с числом разработчиков