АрхитектураПроектирование системИнженер по проектированию распределённых систем

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

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

Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

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

Исторический контекст

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

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

Постановка проблемы

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

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

Подробное решение

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

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

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

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

Главный компромисс состоит в том, что более крупная бизнес-граница упрощает локальную согласованность, но уменьшает независимость масштабирования и выпуска. Более мелкие сервисы дают автономность, однако платой становятся сетевые сбои, наблюдаемость, управление версиями контрактов и eventual consistency.

Ситуация из практики

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

Рассматривались три варианта. Первый — сохранить общую базу и формально объявить каждую таблицу собственностью отдельного сервиса: это быстро, но сохраняет сильную связанность и риск обхода контрактов. Второй — немедленно разнести все таблицы по отдельным базам: границы становятся жёстче, но резко усложняются миграция, согласованность и восстановление. Третий — выделить границы по бизнес-возможностям, сохранив модульный монолит до появления доказанной потребности в физическом разделении.

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

Что кандидаты часто упускают

  1. Как определить, что две сущности должны принадлежать одной границе?

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

  2. Обязательно ли каждому микросервису иметь отдельную физическую базу?

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

  3. Что делать, если один бизнес-процесс всё же пересекает несколько сервисов?

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