Релиз всего приложения из-за одной правки
Изменение текста в корзине требует сборки и выката всего приложения вместе с каталогом, оплатой и админкой. Команды блокируют друг друга в очереди на релиз.
Выберите тему — соберём контекст
Сначала отвечаем на вопрос, нужны ли вам микросервисы вообще. Если да — выделяем их из монолита поэтапно: с владельцем у каждой таблицы, асинхронной интеграцией, контрактами и сквозным трейсингом.
Или сразу: +7 (962) 368-39-51 Telegram
Проблема обычно не в том, что монолит плох, а в том, что его части меняются с разной скоростью и мешают друг другу.
Изменение текста в корзине требует сборки и выката всего приложения вместе с каталогом, оплатой и админкой. Команды блокируют друг друга в очереди на релиз.
Два приложения читают и пишут в одну таблицу пользователей. Изменение схемы ломает оба, а долгая транзакция одного сервиса блокирует работу другого.
Цепочка из шести HTTP-вызовов падает целиком, если тормозит самый слабый участник. Без таймаутов, ретраев с backoff и размыкателей отказ размножается по всей системе.
Списание денег, создание заказа и отправка письма живут в разных сервисах, но нет саги, компенсаций и ключей дедупликации. Двойные списания появляются при первом же сетевом ретрае.
Запрос проходит шесть сервисов и три очереди. Без сквозного трейсинга невозможно сказать, какой шаг добавил две секунды и виноват ли в этом ваш код или внешний API.
Потребитель узнаёт об изменении поля в API в момент релиза поставщика. Версионирования нет, проверки совместимости в конвейере тоже — поломка обнаруживается в продакшене.
Не начинаем с переписывания. Сначала находим реальные швы в системе, затем выделяем сервисы там, где это даёт измеримую выгоду.
Определяем, где заканчивается одна бизнес-область и начинается другая, вместе с вашими доменными экспертами, а не по названиям таблиц.
Работаем по схеме strangler fig: новый сервис встаёт рядом с монолитом, получает трафик постепенно, а старая реализация остаётся страховкой до полного перевода.
Проблемы распределённых систем решаются не распределёнными транзакциями, а идемпотентностью, порядком обработки и компенсациями.
Сервис без описанного контракта и без трейсинга — это чёрный ящик, который ломает соседей и не поддаётся отладке.
Продукт продолжает развиваться во время работ: мы не останавливаем выпуск фичей ради архитектурных изменений.
Собираем карту процессов, сущностей и владельцев данных. Смотрим, где реально возникают конфликты релизов, блокировки и каскадные отказы.
Фиксируем состав сервисов, их контракты, владельцев данных и схему взаимодействия. Считаем стоимость эксплуатации и дежурства для каждого варианта.
Выделяем один-два сервиса: сначала работа рядом с монолитом, затем перевод трафика. Настраиваем для них CI/CD, метрики и контрактные тесты.
По отработанному шаблону выделяем следующие домены, фиксируем стандарты и передаём команде регламент добавления и сопровождения сервисов.
Микросервисы решают организационную проблему: несколько команд не могут независимо менять одну кодовую базу и один релизный цикл. Технические преимущества — независимое масштабирование, разные стеки, изоляция отказов — вторичны и достижимы другими средствами.
Отсюда практический вывод: если систему развивает одна команда из пяти человек, разделение на сервисы почти всегда ухудшит ситуацию. Появятся сетевые вызовы там, где был вызов метода, распределённые транзакции вместо обычных, отдельные конвейеры и дежурства. Выигрыша в скорости не будет, а стоимость эксплуатации вырастет кратно.
Попытка сохранить единую транзакцию на несколько сервисов через двухфазную фиксацию приводит к блокировкам и хрупкости: координатор становится единой точкой отказа, а производительность падает. На практике в распределённой системе мы принимаем согласованность в конечном счёте, а не мгновенную.
Работает это так: сервис в одной локальной транзакции меняет свои данные и записывает событие в таблицу outbox; отдельный процесс публикует событие в брокер; подписчики обрабатывают его идемпотентно, проверяя ключ операции. Если цепочка включает несколько шагов с внешними эффектами — списание денег, создание отправления, — она оформляется сагой с явными компенсациями на каждый шаг. Такой дизайн переживает повторную доставку, падение подписчика и перезапуск брокера, чего нельзя сказать о попытке «сделать одну большую транзакцию».
Ориентир — не количество функций в продукте, а количество независимых потоков изменений. Если две части системы всегда меняются вместе и одним релизом, их разделение даст только накладные расходы. Если же они меняются в разном темпе, требуют разного масштабирования или ими владеют разные команды — граница оправдана.
Мы предпочитаем начинать с модульного монолита: один деплой, но жёсткие внутренние границы, у каждого модуля своя схема данных и публичный интерфейс. Такую систему позже можно выделять по одному модулю, не переписывая код заново. Обратный путь — сборка микросервисов назад в монолит — намного дороже и почти никогда не делается добровольно.
В большинстве случаев для продукта, который развивает команда из 5–15 человек, ответ — нет. Модульный монолит с чёткими границами и отдельными схемами данных даёт почти тот же организационный эффект при заметно меньшей стоимости эксплуатации. Микросервисы оправданы, когда части системы требуют разного темпа изменений или разного масштабирования, у них есть отдельные команды-владельцы и вы готовы платить распределённой отладкой, контрактами и дежурством.
Да. Мы работаем по схеме strangler fig: новый сервис запускается рядом с монолитом, часть трафика постепенно переводится на него, данные синхронизируются двусторонне до момента, когда старая реализация перестаёт получать запросы. Каждый шаг обратим: на любом этапе трафик можно вернуть на монолит, поэтому архитектурное изменение не превращается в риск для продукта.
Разделять по владельцам. Правило простое: у каждой таблицы ровно один сервис, который в неё пишет, остальные получают данные через API или подписку на события. Если две части системы пишут в одну таблицу, они не являются отдельными сервисами, сколько бы конвейеров у них ни было. На время перехода допускаем двойную запись и регулярную сверку, но это временная мера с датой завершения.
Пилотное выделение одного сервиса вместе с конвейером, мониторингом и контрактными тестами обычно занимает 4–8 недель. Полный переход крупной системы — процесс на 6–18 месяцев, идущий параллельно с разработкой продукта. Мы намеренно разбиваем его на этапы так, чтобы после каждого была работающая система и измеримая выгода, а не только промежуточное состояние.
Смежные задачи, которые обычно решаются в одном проекте с этой.
Пришлите схему текущей архитектуры и её болевые точки — вернёмся с оценкой вариантов, рисков и сроков.
Cookie и аналитика
Мы используем необходимые cookie для работы сайта и форм. Аналитические cookie (Яндекс.Метрика, включая запись сессий) подключаем только с вашего согласия — от него можно отказаться. Подробнее: Политика использования cookie и обработка персональных данных.