Монолит vs микросервисы и distributed monolith

О лекции

Сервис выделяют ради независимого деплоя, масштаба и отказов, а не потому что «так модно». Distributed monolith — сеть и операционка микросервисов при общей базе и lock-step релизах.

Проектирование сервисов architecture собеседование

Монолит: один деплой, одна база, локальные вызовы функций. Проще транзакции. Проще трассировка. Один набор миграций. Цена: команда и нагрузка делят судьбу. Отказ модуля может утянуть весь процесс.

Микросервис оправдан, когда релиз, данные и отказ действительно независимы. Своё хранилище. Свой цикл жизни. Свой SLO.

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

Пример. Команда из пяти человек режет «витрину», «заказ» и «уведомления» в три репозитория, но все пишут в одну Postgres. Релизы всё равно вместе. Это не микросервисы. Это монолит с сетевой таксой.

Когда резать

  • Разные циклы жизни: рендер PDF можно катить ежедневно, checkout — раз в неделю с жёстким регрессом.
  • Разный масштаб: пик генерации отчётов не должен требовать столько же реплик, сколько витрина.
  • Явный bounded context: другой язык данных, другие инварианты, другой SLO.
  • Не резать, пока команда одна и домен не устоялся. Стоимость сети, наблюдаемости и дублей контрактов обычно выше выигрыша.

Distributed monolith

Симптомы: общая БД «по таблицам на сервис». Обязательный синхронный вызов цепочки на один клик. Релизы только вместе. Общая библиотека с миграциями.

Много процессов и репозиториев создают иллюзию архитектуры. На деле вы не можете выкатить сервис A без B и миграции в той же базе.

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

// Клиент нажал «купить». Один запрос, пять round-trip и общая БД.
//
//  browser
//     |
//     v
//  order-svc  --SQL--> public.orders, public.users, public.stock
//     | HTTP
//     |----------> billing-svc --SQL--> public.accounts  (та же Postgres)
//     |----------> stock-svc   --SQL--> public.stock     (те же строки)
//     +----------> notify-svc  --SQL--> public.users
//
// Выкатить stock-svc без миграции orders нельзя.
// Падение billing роняет checkout.
// Это не независимость.

Синхронная паутина плюс общая БД — distributed monolith, сколько бы репозиториев ни было.

Типичная ошибка

Резать по слоям: «сервис БД», «сервис валидации» вместо bounded context. Получаете болтливую сеть на каждый use case и общую модель данных. Число сервисов само по себе ничего не гарантирует.

На собеседовании

Критерий — независимый деплой и независимые данные. Назовите, какой отказ изолируется. Модульный монолит — нормальный ответ, пока домен сырой. Distributed monolith — сеть плюс общая БД и lock-step.