К содержимому
14 авг. 2026 г.·8 мин чтения

Граница сервиса по шаблонам доступа к данным

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

Граница сервиса по шаблонам доступа к данным

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

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

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

Начните с транзакций, а не с имен таблиц

Таблицы, записываемые в одной транзакции, дают самый сильный первый сигнал, потому что приложение сейчас считает эти изменения единой операцией с общим успехом или отказом. Если invoice, ledger_entry и customer_balance регулярно меняются под одним идентификатором транзакции, их разделение между сервисами заменит локальный коммит координацией, компенсацией или измененной бизнес нормой.

Имена вводят в заблуждение. Таблица customer может содержать идентификационные данные счета, кредитный статус, предпочтения доставки и денормализованную сумму продаж. Таблица order_status может работать как общая очередь для исполнения заказов и выставления счетов. Префиксы часто отражают команду, создавшую таблицу, а не поведение, которое теперь от нее зависит. Даже внешние ключи описывают только объявленные ссылочные отношения. Они ничего не говорят о ночной программе, которая читает три таблицы, записывает еще две и должна уметь возобновить работу после строки 80 000.

Определяйте транзакцию так, как ее видит база: инструкции между begin и commit или rollback, включая инструкции из триггеров и хранимых процедур. Каждая инструкция с autocommit образует отдельную транзакцию. Для пакетной программы нужен дополнительный идентификатор запуска и контрольной точки, потому что цикл с коммитом после каждых 500 записей выполняет бизнес операцию шире одной транзакции базы.

Для каждого наблюдаемого доступа собирайте как минимум такие поля:

  • идентификатор транзакции и время
  • исполняемый файл, задание, маршрут или точка входа
  • таблица и тип операции
  • число затронутых строк или примерная категория объема
  • цепочка вызовов или имя хранимой процедуры, если оно доступно

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

Матрица совместной записи показывает атомарную работу

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

Предположим, нормализованные трассы попадают в таблицу data_access:

create table data_access (
  captured_at timestamp not null,
  transaction_id varchar(100) not null,
  entry_point varchar(200) not null,
  table_name varchar(200) not null,
  operation varchar(10) not null,
  rows_affected bigint
);

with writes as (
  select distinct transaction_id, table_name
  from data_access
  where operation in ('INSERT', 'UPDATE', 'DELETE')
), pairs as (
  select a.table_name as table_a,
         b.table_name as table_b,
         count(*) as shared_transactions
  from writes a
  join writes b
    on a.transaction_id = b.transaction_id
   and a.table_name < b.table_name
  group by a.table_name, b.table_name
)
select table_a, table_b, shared_transactions
from pairs
order by shared_transactions desc;

Результат имеет вид table_a | table_b | shared_transactions. Самые большие значения требуют изучения, но одних абсолютных чисел недостаточно. Служебное задание может давать основной объем, не поддерживая никакого заметного пользователю инварианта. Редкая проводка в конце года может содержать самое строгое требование к атомарности во всей системе. Добавьте точку входа в группировку, затем сравните одну пару для онлайн запросов, заданий по расписанию, импортов и инструментов операторов.

Нормализуйте вес в обоих направлениях. Если 98 процентов записей в customer_balance происходят вместе с ledger_entry, это ребро важно, даже когда такие транзакции составляют небольшую часть всей работы бухгалтерского регистра. Я использую две условные меры: число транзакций, записывающих A и B, деленное на число всех транзакций, записывающих A; затем обратное отношение. Асимметричный результат часто показывает вспомогательную таблицу, которая входит в более крупный агрегат.

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

Отделяйте бизнес инварианты от привычек реализации

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

Попросите сформулировать отказ одним предложением. Для счета и бухгалтерской записи оно может звучать так: «Финансовый учет не должен признавать счет без соответствующих записей по дебету и кредиту». Для заказа и строки аудита: «Операторам нужна запись о том, кто изменил заказ». Первое правило может потребовать атомарного состояния или тщательно переработанной модели проводки. Второе часто можно перенести в надежное событие или outbox базы данных, не включая таблицу аудита во владение заказами.

Отнесите каждое ребро совместной записи к одной из четырех причин:

  1. Бизнес инвариант требует общего успеха всех изменений.
  2. Ссылочная очистка или каскадная логика поддерживает согласованность сохраненных данных.
  3. Производное значение или индекс синхронно обновляется для ускорения чтения.
  4. Код повторно использовал транзакцию из-за близкого расположения таблиц.

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

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

Блокировки и обработка ошибок дают дополнительные доказательства. Код, который повторяет операцию после взаимной блокировки двух таблиц, преобразует нарушение ограничения в бизнес сообщение или откатывает оба изменения после ошибки проверки, вероятно, зависит от их общей судьбы. Зафиксируйте точное ограничение или правило восстановления. Формулировка «эти таблицы связаны» слишком расплывчата для проекта миграции.

Междоменные чтения создают другой вид долга

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

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

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

Назначьте каждому пересекающему границу чтению класс свежести:

  • точное на момент решения
  • ограниченная задержка с указанным максимумом
  • последнее известное значение с последующей сверкой
  • исторический снимок
  • только для отображения

Такая классификация превращает размытую зависимость «заказам нужны данные клиентов» в контракт. Имена клиентов только для отображения могут храниться в проекции заказов. Проверка кредитного лимита может требовать, чтобы домен клиента владел резервом. Тогда сервис заказов просит зарезервировать сумму, а не получает число и принимает решение самостоятельно.

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

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

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

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

Граница ломается, если ее пересекает инвариант

Прочитайте разноязычное дерево исходников
COBOL, JCL, PL/SQL, скрипты и клиенты анализируются вместе, а не отдельными проектами.

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

Рассмотрим процедуру заказа, которая выполняет в одной транзакции такие действия:

  1. Читает доступный кредит клиента с блокировкой строки.
  2. Вставляет заказ и его позиции.
  3. Увеличивает зарезервированную кредитную нагрузку клиента.
  4. Вставляет запись аудита и выполняет commit.

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

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

Резервированию нужны состояния и правила времени, а не оптимистичное имя события. reserve должен возвращать один результат для одного идентификатора. confirm должен выдерживать повторы. Истечение срока должно учитывать позднее подтверждение. Операторам нужен обзор резервов, которые не достигли конечного состояния. Если организация не может назвать эти правила, она не убрала распределенную транзакцию, а только переименовала неопределенность.

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

Пакетные задания показывают пропуски онлайн трасс

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

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

Частота коммитов пакетной программы имеет значение. Программа, которая читает все непроведенные счета, создает бухгалтерские записи, отмечает исходные строки и делает коммит после каждых 500 элементов, имеет как минимум три области:

  • транзакция базы для каждого блока
  • контрольная точка возобновления запуска
  • бизнес требование для всего периода проводки

Разделение сервисов может сохранить коммиты блоков, но сломать возобновление. Представьте, что новый сервис регистра принял 430 записей, после чего вызывающая программа остановилась. Старая программа запускается с последней контрольной точки и отправляет записи повторно. Без стабильного исходного идентификатора и идемпотентного приема цель создает дубликаты. При идемпотентности без сверки источник по-прежнему может показывать 70 ожидающих элементов, хотя регистр их принял.

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

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

Сначала назначьте владельцев таблиц, затем проектируйте API

Завершите менее чем за тридцать дней
Каждое переписывание поставляется менее чем за 30 дней с новой архитектурой и доказательствами паритета.

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

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

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

Команды API должны выражать решения, принадлежащие вызываемому сервису. reserveCredit(orderId, amount) надежнее, чем getAvailableCredit(customerId) с последующим расчетом на вызывающей стороне. postInvoice(invoiceId, lines) надежнее открытых операций CRUD над таблицами регистра. Команда позволяет владельцу защищать свой инвариант при изменении хранилища.

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

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

Оценивайте границы по объему необходимой работы

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

Для каждой предлагаемой границы запишите:

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

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

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

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

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

Докажите границу теневым поведением

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

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

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

Включите случаи, нагружающие границу:

  1. успешные команды с записью только у одного владельца
  2. отклоненные команды после удаленного резервирования или проверки
  3. повторы после таймаутов и дублированной доставки
  4. возобновление пакета с каждой позиции контрольной точки
  5. устаревшие или отсутствующие данные проекции

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

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

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

Первое выделение должно убрать транзакционную границу

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

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

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

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

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

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

Вопросы

Какое доказательство границы сервиса самое сильное?

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

Определяют ли внешние ключи границы сервисов?

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

Сколько продакшен трафика собирать для анализа границ?

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

Для каждого междоменного чтения нужен синхронный API?

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

Как найти доступ к данным внутри процедур и триггеров?

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

Может ли брокер сообщений заменить распределенную транзакцию?

Брокер переносит сообщения, но не определяет инвариант. Все равно нужны переходы состояния у владельца, идемпотентность, правила повторов, сверка и правило частичного выполнения.

Должны ли отчетные соединения влиять на операционные границы?

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

Что делать, если двум доменам нужны атомарные записи?

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

Как обеспечить владение таблицами до выделения сервиса?

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

Как доказать работоспособность выбранной границы?

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