АрхитектураМикросервисы и интеграцииАрхитектор распределённых систем

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

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

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

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

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

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

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

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

Цена этого подхода — eventual consistency. Локальная копия обновляется не одновременно с источником, поэтому контракт должен описывать не только структуру ставки, но и её версию, период действия и допустимую свежесть.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  1. Достаточно ли хранить только время последнего обновления?

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

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

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

  1. Что делать, если ставка изменилась во время оформления заказа?

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