Deadline.by
Deadline.by

Опишите задачу — посчитаем смету и сроки за день

Автоматизация·8 мин чтения·Антон, ведущий разработчик Deadline

Микросервисная архитектура: когда нужна, а когда вредит

Микросервисная архитектура: чем отличается от монолита, какую цену за неё платят и по каким признакам понять, что разделение назрело. Без моды на архитектуру.

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

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

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

Разница не в количестве кода, а в том, где проходят границы и что происходит при отказе.

Монолит Микросервисы
Выкладка Вся система целиком По частям, независимо
Отказ части Обычно падает всё Остальное продолжает работать, если предусмотрено
Вызов между частями Внутри процесса, наносекунды По сети, миллисекунды и возможная ошибка
База данных Одна, транзакции честные Своя у каждого, согласованность отложенная
Отладка Один процесс, один лог Трассировка через несколько сервисов
Порог входа Низкий Высокий: нужна инфраструктура

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

Монолит Микросервисы Одно приложение База Шлюз и проверка доступа Сервис Сервис Сервис База База База один процесс между сервисами — очередь сообщений Цена разделения — сеть там, где был обычный вызов функции — согласованность данных становится отложенной — нужна сквозная трассировка запроса — среду нужно уметь поднять целиком Всё это оплачивается до первой выгоды, а не после
Разделение — это обмен: простота внутри каждого сервиса покупается сложностью между ними.

Какую цену платят за микросервисы

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

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

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

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

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

Мартин Фаулер, один из авторов самого термина, прямо рекомендует начинать с монолита и выделять сервисы позже — его разбор компромиссов собран в статье Microservices и в заметке MonolithFirst.

По каким признакам разделение назрело

Ни один из признаков не про количество строк кода. Все они про то, что части системы начали мешать друг другу.

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

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

Как выносить постепенно

Рабочая последовательность выглядит скучно и именно поэтому работает.

  1. Выберите участок с понятной границей. Уведомления, генерация документов, обработка файлов, выгрузки. У таких задач мало общих данных с остальной системой.
  2. Поставьте очередь между монолитом и новым сервисом. Тогда падение сервиса не роняет основную систему — сообщения подождут.
  3. Дайте ему собственное хранилище. Сервис, который ходит в общую базу монолита, микросервисом не является: вы получили сетевые расходы, не получив независимости.
  4. Настройте наблюдаемость до переноса нагрузки. Сквозной идентификатор запроса и общий сбор логов — раньше, чем боевой трафик.
  5. Оцените результат через два месяца. Стало ли легче выкладывать, снизилось ли время простоя, уменьшилось ли ожидание между командами. Нет — следующий участок не выносим.

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

Три ошибки, которые обесценивают разделение

Общая база на всех. Сервисы вынесены, а данные лежат в одной схеме, и любое изменение таблицы задевает половину системы. Это распределённый монолит: сетевые расходы уже платятся, независимости ещё нет.

Сервисы по слоям, а не по смыслу. Отдельно сервис работы с базой, отдельно сервис бизнес-логики, отдельно сервис интерфейса. Любая новая функция требует правки во всех трёх и согласованной выкладки — то есть ровно того, ради избавления от чего разделение и затевалось. Проверка, которой мы пользуемся: если типовая задача закрывается изменением в одном сервисе, граница проведена верно; если задевает три — граница легла по слоям. Как это выглядело на реальной системе, разобрано в кейсе платформы на микросервисах.

Синхронные цепочки вызовов. Один сервис дёргает следующий, тот — ещё один, и вся цепь укладывается в один пользовательский запрос. Достаточно отказать любому звену, чтобы отказал весь запрос: разделённая система получилась менее надёжной, чем монолит, за который платить не пришлось бы. Лечится очередью и ответом «принято, результат придёт позже» там, где мгновенный ответ не обязателен.

Короткий вывод

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

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

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

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

Частые вопросы

01Что такое микросервисная архитектура простыми словами?

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

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

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

03Микросервисы работают быстрее монолита?

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

04Можно ли перейти на микросервисы постепенно?

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

Ещё по теме

Заполнить бриф