Типы сообщений: сколько информации должны содержать сообщения?
В настоящее время мы начинаем транслировать события из одного центрального приложения в другие, возможно, заинтересованные потребительские приложения, и у нас есть различные варианты среди членов нашей команды о том, сколько мы должны поместить в наши опубликованные сообщения.
Общая идея / архитектура заключается в следующем:
- В заявке производителя:
- пользователь взаимодействует с некоторыми объектами (Aggregate Roots в смысле DDD), которые могут быть созданы / изменены / удалены
- В зависимости от того, что происходит, генерируются события домена (например: EntityXCreated, EntityYDeleted, EntityZTransferred и т. Д., Т. Е. Не только CRUD, но в основном)
- Полученные события преобразуются / преобразуются в сообщения, которые мы отправляем на RabbitMQ Exchange.
- в RabbitMQ (мы используем RabbitMQ, но я считаю, что вопрос на самом деле не зависит от технологии):
- мы определяем очередь для каждого потребляющего приложения
- привязки соединяют обмен с очередями потребителя (возможно, с фильтрацией сообщений)
- В потребляющих приложениях
- приложение потребляет и обрабатывает сообщения из своей очереди
Основываясь на корпоративных шаблонах интеграции, мы пытаемся определить формат Canonical для наших опубликованных сообщений и колеблемся между двумя подходами:
Минималистские сообщения / event-store-ish: для каждого события, публикуемого моделью домена, сгенерируйте сообщение, которое содержит только релевантные части совокупного корня (например, когда обновление выполнено, публикуйте только информацию об обновленном разделе совокупного корня, более или менее совпадающего с процессом, который проходит конечный пользователь при использовании нашего приложения)
Pros
- маленький размер сообщения
- очень специализированные типы сообщений
- близко к "Доменным событиям"
Cons
- проблематично, если заказ на доставку не гарантирован (то есть что, если сообщение об обновлении получено до создания сообщения?)
- потребители должны знать, на какие типы сообщений подписываться (возможно, требуется большой список / знание домена)
- Что, если состояние потребителя и состояние производителя не синхронизированы?
- как обращаться с новым потребителем, который регистрируется в будущем, но не знает обо всех прошедших событиях
Полностью содержащиеся сообщения idempotent-ish: для каждого события, публикуемого моделью предметной области, сгенерируйте сообщение, которое содержит полный моментальный снимок агрегированного корня на данный момент времени, следовательно, в действительности обрабатывая только 2 вида сообщений "Создать или обновить" и "Удалить" (+ метаданные с более конкретной информацией, если необходимо)
Pros
- идемпотент (декларативные сообщения о том, что "это то, на что похожа истина, синхронизируйте себя так, как можете")
- меньшее количество форматов сообщений для поддержки / обработки
- позволяют постепенно исправлять ошибки синхронизации потребителей
- потребитель автоматически обрабатывает новые доменные события, пока получающееся сообщение следует канонической модели данных
Cons
- большая полезная нагрузка сообщения
- менее чистый
Вы бы порекомендовали подход по сравнению с другим?
Есть ли другой подход, который мы должны рассмотреть?
1 ответ
Есть ли другой подход, который мы должны рассмотреть?
Вы могли бы также рассмотреть вопрос об отсутствии утечки информации из службы, выступающей в качестве технического органа для этой части бизнеса
Что примерно означает, что ваши события имеют идентификаторы, так что заинтересованные стороны могут знать, что интересующий объект изменился, и могут запрашивать полномочия для обновления состояния.
для каждого события, опубликованного моделью предметной области, создайте сообщение, содержащее полный моментальный снимок совокупного корня на данный момент времени
Это также имеет дополнительное условие: любое изменение представления агрегата также подразумевает изменение схемы сообщения, которая является частью API. Таким образом, внутренние изменения в агрегатах начинают распространяться через границы вашего сервиса. Если агрегаты, которые вы внедряете, представляют конкурентное преимущество для вашего бизнеса, вы, вероятно, захотите быстро адаптироваться; рябь добавляет трения, которые замедляют вашу способность меняться.
Что, если состояние потребителя и состояние производителя не синхронизированы?
Насколько я могу судить, эта проблема указывает на ошибку проектирования. Если потребителю нужно состояние, то есть представление, построенное из истории агрегата, то ему следует получать это представление от производителя, а не пытаться собрать его из набора наблюдаемых сообщений.
То есть, если вам нужно состояние, вам нужна история (полная, упорядоченная). Все, что вам на самом деле говорит отдельное событие, - это то, что история изменилась, и вы можете удалить свою ранее сохраненную историю.
Опять же, отзывчивость к изменениям: если вы измените реализацию производителя, а потребители также попытаются собрать воедино свою собственную копию истории, то ваши изменения будут распространяться через границы обслуживания.