Где и когда запрашивать ФИО пользователей в микросервисной архитектуре: при создании, хранении или извлечении сообщений?
У меня микросервисная архитектура, в которой реализована система обмена сообщениями. Устроено всё следующим образом:
- IdentityService — отдельный микросервис, где хранятся ФИО (имена) пользователей.
- MailboxService — сервис, который управляет почтовыми ящиками и сообщениями. Здесь хранятся сообщения, айдишники отправителя и получателя, а также email-адреса (email — часть Mailbox).
- GatewayService — API-слой, выступает оркестратором между сервисами.
Каждое сообщение содержит senderId и recipientId, а также имена этих пользователей (senderName, recipientName). Проблема в том, что имена живут только в IdentityService, а сообщения создаются и хранятся в MailboxService.
Я не могу понять, где правильнее подставлять ФИО и какие есть архитектурные компромиссы. Понимаю, что это типичная боль микросервисов, а потому мне интересно мнение сообщества. Вот варианты, которые я рассматриваю:
⸻
Вариант 1: Получать имена во время создания сообщения в GatewayService
GatewayService не создает письмо, но обращается к MailboxService. В этот момент он запрашивает имена из IdentityService и передаёт их в MailboxService вместе с остальными данными. MailboxService сохраняет senderName, recipientName прямо в Message.
Плюсы:
- MailboxService ничего не знает про IdentityService.
- Данные в сообщении самодостаточны, клиенту ничего дополнительно не нужно подгружать.
Минусы:
- Дублирование данных (имена хранятся и в Identity, и в каждом сообщении).
- При смене имени у пользователя старые сообщения сохраняют старое имя.
- GatewayService становится “толстым”, тянет логику из двух сервисов.
⸻
Вариант 2: Сохранять имя владельца внутри Mailbox
Когда создаётся почтовый ящик, в него вместе с ID пользователя сохраняется его ФИО. При создании сообщений имя отправителя берётся из Mailbox, а имя получателя — через внешний вызов или тоже из кэша.
Плюсы:
- Централизация: Mailbox знает всё про своего владельца.
- MailboxService может самостоятельно создавать сообщения без помощи GatewayService.
Минусы:
- Повтор данных и потенциальное устаревание при изменении ФИО.
- MailboxService начинает хранить то, что по смыслу принадлежит Identity — нарушение SRP.
⸻
Вариант 3: Не хранить имена вообще, подставлять при извлечении сообщений
MailboxService хранит только ID отправителя и получателя. Когда сообщения извлекаются через GatewayService, он собирает пачку ID и делает запрос в IdentityService, чтобы подставить ФИО.
Плюсы:
- Чистая архитектура: каждый сервис знает только то, что должен.
- Имена всегда актуальны.
Минусы:
- Усложнение логики извлечения (нужно делать join-like запрос).
- Производительность — при большом числе сообщений и пользователей запросы к Identity могут стать узким местом. Благо она не предполагает высокой нагрузки (закрытая сеть, слабый трафик и юзеров всего пару тысяч)
⸻
Вопрос:
Какой из этих подходов является более корректным и принятым в микросервисной архитектуре, когда речь идёт об использовании “вторичных” данных другого сервиса (вроде ФИО), которые не участвуют в бизнес-логике, а нужны только для отображения?
Ответы (1 шт):
Лучший подход зависит от конкретных требований и ограничений вашего проекта. Однако, в вашем случае, оптимизированный вариант 3 (подстановка имен при извлечении с использованием кэширования и пакетных запросов) представляется наиболее разумным компромиссом между чистотой архитектуры, производительностью и актуальностью данных. CQRS - хороший вариант для рассмотрения в будущем, если требования к масштабируемости возрастут.