Два года на микросервисах: почему мы всё снесли и вернулись к модульному монолиту

Рейтинг: 43.6% · 6 голосов
Технические статьи, разборы и лонгриды от сообщества Cyberlake.
Ответить
Аватара пользователя
rburr
Сообщения: 77
Зарегистрирован: 12 май 2026, 17:53

Два года на микросервисах: почему мы всё снесли и вернулись к модульному монолиту

Сообщение rburr »

В 2022 мы распилили монолит на микросервисы, потому что так делали все. В 2025 собрали всё обратно в модульный монолит, и это было лучшее архитектурное решение за пять лет существования продукта. Расскажу с цифрами, где именно болело и почему обратный путь оказался не позором, а взрослением.

Контекст: b2b SaaS для логистики, около 4000 активных компаний-клиентов, команда из 9 бэкендеров. Стек на момент распила: монолит на PHP 8.1 плюс пара воркеров. К концу 2024 у нас было 23 сервиса на Go и PHP, Kubernetes в Yandex Cloud, Kafka, gRPC между сервисами, трейсинг в Tempo.

Боль номер один, распределённые транзакции:

Классика: создание заказа трогает биллинг, остатки на складе и уведомления. В монолите это был один BEGIN ... COMMIT. В микросервисах это сага с компенсациями плюс transactional outbox в каждом сервисе:

Код: Выделить всё

CREATE TABLE outbox (
    id           bigserial PRIMARY KEY,
    aggregate_id uuid NOT NULL,
    event_type   text NOT NULL,
    payload      jsonb NOT NULL,
    created_at   timestamptz DEFAULT now()
);
Выглядит академично, работает до первого частичного отказа. Реальный инцидент: деньги с баланса клиента списались, заказ не создался, компенсирующая транзакция упала по таймауту, и саппорт два дня руками сверял балансы по выгрузке. Каждый бизнес-процесс, проходящий через три и больше сервисов, превращается в отдельный проект по обработке частичных отказов, идемпотентности и ретраев. Мы потратили на эту обвязку, по грубой оценке из джиры, человеко-год. Бизнес-ценность обвязки: ноль.

Боль номер два, latency:

Создание заказа в монолите: p99 около 80 мс. После распила цепочка проходила через 6 сетевых хопов, и p99 вырос до 420 мс. gRPC с keepalive и пулами соединений срезал до примерно 280, но дальше упёрлись: каждый хоп это сериализация, сеть, очередь на принимающей стороне. Можно переписать цепочку на асинхронные события, и мы переписали часть, но тогда фронту нужны промежуточные статусы вида "заказ создаётся", поллинг или вебсокеты, и продуктовая команда смотрит на тебя с ненавистью, потому что раньше кнопка просто работала.

Боль номер три, инфраструктура и деньги:

Монолит жил на трёх виртуалках. Микросервисный ландшафт: 14 нод под Kubernetes, кластер Kafka из трёх брокеров, отдельные базы у половины сервисов, Prometheus, Tempo, Loki. Счёт в Yandex Cloud вырос с примерно 90 тысяч до 480 тысяч рублей в месяц. Плюс по факту целая ставка инженера уходила на платформу: апгрейды кластера, helm-чарты, сертификаты, дрейф конфигов между окружениями. Для команды из 9 человек это непозволительный налог.

Боль номер четыре, дебаг:

Инцидент в монолите: открываешь стектрейс, видишь строку. Инцидент в микросервисах: собираешь трейс по correlation id, выясняешь, что половина спанов потерялась, потому что один сервис не пробрасывал заголовки, дальше читаешь логи трёх сервисов с тремя разными форматами времени. Среднее время разбора инцидента у нас выросло с 40 минут до трёх с лишним часов, это по постмортемам, не по ощущениям.

Что мы сделали:

Не склеили всё обратно в шар, а собрали модульный монолит на Go. Один бинарь, одна PostgreSQL 16, внутри модули с жёсткими границами: billing, orders, warehouse, notifications. У каждого модуля публичный интерфейс (отдельный пакет api) и приватная внутрянка. Границы проверяет go-arch-lint в CI:

Код: Выделить всё

deps:
  orders:
    mayDependOn:
      - billing-api
      - warehouse-api
  billing:
    mayDependOn: []
Любая попытка дотянуться до чужих таблиц или внутренних структур валит сборку. Это принципиальный момент: модульный монолит без машинной проверки границ деградирует в обычный за год.

Миграция заняла 7 месяцев фоном от основной работы. Сервисы переезжали по одному, данные сливали в общую базу через logical replication, на каждом шаге был feature-флаг для отката. Ни одного даунтайма дольше пяти минут.

Что получили: p99 создания заказа 90 мс без всякой оптимизации, просто потому что исчезла сеть. Счёт за облако 140 тысяч в месяц. Деплой одной командой вместо оркестрации релизного поезда из десятка сервисов. Локальная разработка это docker compose с приложением и базой, а не 23 контейнера, съедающие 32 гига на ноутбуке. Онбординг джуна сократился с месяца до недели.

Когда микросервисы всё-таки оправданы:

Мы не стали фанатиками обратного карго-культа. Два сервиса остались отдельными: рендеринг PDF-накладных (CPU-bound, скейлится независимо, его падение никого не волнует) и шлюз интеграций с API перевозчиков (зоопарк SOAP и непредсказуемые таймауты, изоляция защищает основное приложение).

Микросервисы честно работают, когда: у вас десятки команд и нужны независимые релизные циклы; есть компоненты с принципиально разным профилем нагрузки; нужна изоляция по безопасности или комплаенсу (платёжный контур, персональные данные по 152-ФЗ); вы реально упёрлись в вертикальный потолок одной машины, что в 2026 при серверах со 192 ядрами и терабайтом памяти случается куда реже, чем принято думать. Ни один пункт из списка не звучит как "так модно" и не описывает команду из 9 человек.

Выводы:

Микросервисы это не архитектура, а организационный инструмент с огромным ценником. Платить его имеет смысл, когда стоимость координации людей превышает стоимость владения распределённой системой. Модульный монолит даёт 80 процентов пользы (границы, тестируемость, явные контракты между модулями) за 5 процентов цены. И если границы выстроены честно, вынести модуль в отдельный сервис потом это вопрос недель. Обратный путь, как мы выяснили на себе, занимает 7 месяцев и стоит сильно дороже.
👍2 ❤️ 🔥1 😄 🤔
✔ Лучший ответ сформирован автоматически — nashnet
Прошли почти то же самое в e-com, только у нас было 40+ сервисов на 14 человек. Подпишусь под каждым словом про дебаг, у нас на один инцидент с потерянным заказом ушло однажды два рабочих дня, и причиной оказался ретрай с неидемпотентным консьюмером. Единственное, что добавлю: модульный монолит сам по себе не панацея. Если за границами не следить, через год получите тот же big ball of mud, только…
Перейти к ответу →
Аватара пользователя
nashnet
Сообщения: 16
Зарегистрирован: 15 май 2026, 08:53

Re: Два года на микросервисах: почему мы всё снесли и вернулись к модульному монолиту

Сообщение nashnet »

✔ Лучший ответ — сформирован автоматически
Прошли почти то же самое в e-com, только у нас было 40+ сервисов на 14 человек. Подпишусь под каждым словом про дебаг, у нас на один инцидент с потерянным заказом ушло однажды два рабочих дня, и причиной оказался ретрай с неидемпотентным консьюмером.

Единственное, что добавлю: модульный монолит сам по себе не панацея. Если за границами не следить, через год получите тот же big ball of mud, только без сетевых вызовов. У нас линтер границ появился через полгода после склейки, и за эти полгода два модуля успели срастись намертво, расцепляли потом месяц. Так что пункт про go-arch-lint в CI это не деталь, это половина успеха.

Kafka мы кстати оставили, для событий наружу (аналитика, нотификации партнёрам) она нормальна. Проблемой были именно внутренние синхронные цепочки.
👍1 ❤️ 🔥1 😄 🤔
Аватара пользователя
marty777
Сообщения: 3
Зарегистрирован: 17 май 2026, 01:35

Re: Два года на микросервисах: почему мы всё снесли и вернулись к модульному монолиту

Сообщение marty777 »

Читаю и вижу классическую ошибку выжившего. У вас не микросервисы не взлетели, у вас не было платформенной команды. 23 сервиса на 9 бэкендеров это два с половиной сервиса на человека, разумеется вы утонули в обвязке. В нормально построенной конторе есть платформа: шаблон сервиса с готовым CI, автоматический проброс trace-заголовков из коробки, прикладной разработчик про k8s вообще не думает. Все перечисленные боли это боли самопала, а не архитектурного стиля. Делать из этого вывод "микросервисы плохие" примерно как разбить машину и написать статью против автомобилей.
👍2 ❤️1 🔥 😄 🤔1
Аватара пользователя
juniorredteam
Сообщения: 66
Зарегистрирован: 11 май 2026, 07:16

Re: Два года на микросервисах: почему мы всё снесли и вернулись к модульному монолиту

Сообщение juniorredteam »

rburr писал(а):каждый хоп это сериализация, сеть, очередь на принимающей стороне
Вот тут придерусь. 420 мс на 6 хопов это не "физика", внутри одной зоны доступности RTT полмиллисекунды, 6 хопов это 3 мс сети чистыми. Остальные 300+ мс вы потеряли сами: коннекты на каждый запрос, синхронные походы в базу под чужим вызовом, отсутствие пулов до того как вы их прикрутили. В монолите эта же кривизна просто размазалась бы по общему профилю и никто бы её не заметил.

Но в этом и пуанта, которую вы зря не выделили: распределёнка делает любую неаккуратность видимой и дорогой в поиске. Так что с выводом согласен, с формулировкой нет.
👍 ❤️ 🔥 😄 🤔
Аватара пользователя
asynclover
Сообщения: 70
Зарегистрирован: 13 май 2026, 04:35

Re: Два года на микросервисах: почему мы всё снесли и вернулись к модульному монолиту

Сообщение asynclover »

Самое интересное в статье уместилось в одно предложение про logical replication. Можно подробнее? У сервисов же были свои схемы, наверняка пересекались имена таблиц и конфликтовали последовательности id. Вы раскладывали таблицы по схемам постгреса под каждый модуль или прямо мержили в public с переименованием? И как жили в переходный период, когда часть данных уже в общей базе, а сервис-владелец ещё пишет в свою?

Спрашиваю не из любопытства, у нас похожая задача висит: 11 сервисов, причём две базы это MongoDB, и я пока не решил, перетаскивать их содержимое в jsonb или оставить монгу сбоку как legacy. Если был опыт с не-постгресовыми источниками, расскажите.
👍1 ❤️1 🔥 😄 🤔
Аватара пользователя
rawgoblin
Сообщения: 39
Зарегистрирован: 13 май 2026, 07:42

Re: Два года на микросервисах: почему мы всё снесли и вернулись к модульному монолиту

Сообщение rawgoblin »

marty777 писал(а):У вас не микросервисы не взлетели, у вас не было платформенной команды
И где её взять конторе из 9 бэкендеров? Платформенная команда это ещё минимум 3-4 инженера, по нынешнему рынку тысяч 800-900 фонда оплаты в месяц, не считая что хороших платформенных людей ещё и не нанять. Совет уровня "просто будьте большой компанией".

Забавно, что вы с автором на самом деле согласны: он прямым текстом пишет, что микросервисы оправданы при десятках команд. Вы спорите с тезисом, которого в статье нет.
👍 ❤️ 🔥 😄 🤔
Аватара пользователя
regexlover
Сообщения: 18
Зарегистрирован: 21 май 2026, 11:59

Re: Два года на микросервисах: почему мы всё снесли и вернулись к модульному монолиту

Сообщение regexlover »

480 тысяч в месяц на инфру при девяти разработчиках это жёстко, у нас весь прод вместе со стейджингом дешевле выходит. Спасибо за цифры до и после, унесу финдиректору как аргумент: нам распил на микросервисы второй квартал подряд продают внешние консультанты, и до сих пор все возражения были на уровне ощущений.
👍1 ❤️ 🔥 😄 🤔
Ответить
Поделиться темой: ✈ Telegram VK

Вернуться в «Статьи и лонгриды»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость