Рассмотрим пример системы, в которой три сервиса используют одни и те же счета, при этом у каждого сервиса — собственная база:

  • сервис показывает подробности по счёту;
  • сервис считает агрегаты по клиенту;
  • сервис формирует рекомендации продуктов.

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

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

FDW

PostgreSQL Foreign Data Wrapper позволяет обращаться к удалённым таблицам и включать их в SQL-запросы. Это сохраняет данные по счетам в одном месте и позволяет выполнять джойны средствами базы.

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

Вызовы API

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

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

Локальные проекции

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

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

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

Подход Что даёт Ограничение
FDW SQL-запросы к удалённым таблицам Связывает задержку и доступность нескольких баз
API Сервисы сохраняют контроль над своими данными Джойны и массовая обработка усложняются на стороне приложения
Локальные проекции Каждая база подготовлена для своего чтения Нужны доставка, повторы и контроль расхождений

Что потребуется для локальных проекций

Сервис приёма должен фиксировать, какие изменения дошли до каждой базы. Повторная обработка не должна создавать дубликаты или затирать более новые данные. Ошибки доставки нужно повторять, а отставание — измерять.

Также понадобится сверка с источником и процедура восстановления проекции. Если обновления приходят не по порядку, система должна определить актуальную версию счёта и не применить старое состояние поверх нового.

Решение

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

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