3

WebTech

Личный кабинет

Проекты, коммерческие предложения, документы и отчёты — в одном месте.

Войти Зарегистрироваться Забыли пароль?
Микросервисная архитектура

Разделяем систему по границам домена без большой переписи

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

Или сразу: +7 (962) 368-39-51 Telegram

DDD
границы по бизнес-возможностям
strangler
постепенное выделение вместо переписи
at-least-once
идемпотентность и outbox
контракты
OpenAPI и проверка совместимости
Задачи

Почему монолит начинает мешать

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

Релиз всего приложения из-за одной правки

Изменение текста в корзине требует сборки и выката всего приложения вместе с каталогом, оплатой и админкой. Команды блокируют друг друга в очереди на релиз.

Общие таблицы вместо контрактов

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

Каскадные отказы на синхронных вызовах

Цепочка из шести HTTP-вызовов падает целиком, если тормозит самый слабый участник. Без таймаутов, ретраев с backoff и размыкателей отказ размножается по всей системе.

Распределённые операции «на глазок»

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

Непонятно, где теряется время

Запрос проходит шесть сервисов и три очереди. Без сквозного трейсинга невозможно сказать, какой шаг добавил две секунды и виноват ли в этом ваш код или внешний API.

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

Потребитель узнаёт об изменении поля в API в момент релиза поставщика. Версионирования нет, проверки совместимости в конвейере тоже — поломка обнаруживается в продакшене.

Решения

Что мы делаем

Не начинаем с переписывания. Сначала находим реальные швы в системе, затем выделяем сервисы там, где это даёт измеримую выгоду.

Границы и декомпозиция

Определяем, где заканчивается одна бизнес-область и начинается другая, вместе с вашими доменными экспертами, а не по названиям таблиц.

  • Картирование домена и выделение ограниченных контекстов
  • Анализ связности: где проходит настоящий шов, а где сущности меняются вместе
  • Обоснованное решение «монолит, модульный монолит или сервисы»
  • Приоритеты: что выделять первым, а что не выделять вообще

Выделение сервисов из монолита

Работаем по схеме strangler fig: новый сервис встаёт рядом с монолитом, получает трафик постепенно, а старая реализация остаётся страховкой до полного перевода.

  • Поэтапный перевод трафика с возможностью вернуть его на монолит
  • Разделение данных: у каждой таблицы ровно один сервис-владелец
  • Двойная запись и последующая сверка на время перехода
  • Постепенный вывод старого кода вместо одномоментной переписи

Интеграция и согласованность

Проблемы распределённых систем решаются не распределёнными транзакциями, а идемпотентностью, порядком обработки и компенсациями.

  • Асинхронный обмен через RabbitMQ или Kafka вместо цепочек HTTP-вызовов
  • Transactional outbox: событие публикуется в одной транзакции с изменением данных
  • Идемпотентные обработчики и ключи дедупликации для доставки at-least-once
  • Саги с компенсациями для операций, затрагивающих несколько сервисов

Контракты и наблюдаемость

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

  • OpenAPI и AsyncAPI как источник правды, генерация клиентов и моков
  • Consumer-driven contract tests: поставщик узнаёт о поломке до релиза
  • Версионирование API и понятная политика устаревания полей
  • Сквозной трейсинг и correlation id через сервисы и очереди
Процесс

Как проходит переход к сервисам

Продукт продолжает развиваться во время работ: мы не останавливаем выпуск фичей ради архитектурных изменений.

  1. 01 1–2 недели

    Картирование домена

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

  2. 02 2–3 недели

    Проектирование границ

    Фиксируем состав сервисов, их контракты, владельцев данных и схему взаимодействия. Считаем стоимость эксплуатации и дежурства для каждого варианта.

  3. 03 4–8 недель

    Пилотное выделение

    Выделяем один-два сервиса: сначала работа рядом с монолитом, затем перевод трафика. Настраиваем для них CI/CD, метрики и контрактные тесты.

  4. 04 по этапам

    Тиражирование практики

    По отработанному шаблону выделяем следующие домены, фиксируем стандарты и передаём команде регламент добавления и сопровождения сервисов.

Микросервисы — это в первую очередь про организацию

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

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

Почему распределённые транзакции не решаются транзакциями

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

Работает это так: сервис в одной локальной транзакции меняет свои данные и записывает событие в таблицу outbox; отдельный процесс публикует событие в брокер; подписчики обрабатывают его идемпотентно, проверяя ключ операции. Если цепочка включает несколько шагов с внешними эффектами — списание денег, создание отправления, — она оформляется сагой с явными компенсациями на каждый шаг. Такой дизайн переживает повторную доставку, падение подписчика и перезапуск брокера, чего нельзя сказать о попытке «сделать одну большую транзакцию».

Сколько сервисов действительно нужно

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

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

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

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

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

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

Пилотное выделение одного сервиса вместе с конвейером, мониторингом и контрактными тестами обычно занимает 4–8 недель. Полный переход крупной системы — процесс на 6–18 месяцев, идущий параллельно с разработкой продукта. Мы намеренно разбиваем его на этапы так, чтобы после каждого была работающая система и измеримая выгода, а не только промежуточное состояние.

Нужно понять, где проходят границы вашей системы?

Пришлите схему текущей архитектуры и её болевые точки — вернёмся с оценкой вариантов, рисков и сроков.