消息类型:消息应该包含多少信息?
Message types : how much information should messages contain?
我们目前正开始将事件从一个中央应用程序广播到其他可能感兴趣的消费者应用程序,我们的团队成员对我们应该在已发布的消息中放入多少有不同的选择.
一般idea/architecture如下:
- 在生产者应用程序中:
- 用户与某些实体(DDD 意义上的聚合根)进行交互,这些实体可以是 created/modified/deleted
- 根据正在发生的事情,引发域事件(例如:EntityXCreated、EntityYDeleted、EntityZTransferred 等......即不仅是 CRUD,而且主要是)
- 引发的事件 translated/converted 到我们发送到 RabbitMQ Exchange 的消息中
- in RabbitMQ (我们正在使用 RabbitMQ,但我认为这个问题实际上与技术无关):
- 我们为每个消费应用程序定义一个队列
- 绑定将交换连接到消费者队列(可能带有消息过滤)
- 在消费应用程序中
- 应用程序使用并处理其队列中的消息
基于Enterprise Integration Patterns,我们正在尝试为我们发布的消息定义规范格式,并且在两种方法之间犹豫不决:
Minimalist messages / event-store-ish :对于域模型发布的每个事件,生成一个仅包含聚合根相关部分的消息(例如,完成更新后,仅发布有关聚合根更新部分的信息,或多或少与最终用户在使用我们的过程时经历的过程相匹配申请)
优点
- 小邮件大小
- 非常专业的消息类型
- 接近"Domain Events"
缺点
- 如果不能保证交付顺序会有问题(即如果在创建消息之前收到更新消息怎么办?)
- 消费者需要知道要订阅哪些消息类型(可能需要一个大列表/领域知识)
- 如果消费者状态和生产者状态不同步怎么办?
- 如何处理未来注册但不了解所有过去事件的新消费者
Fully-contained idempotent-ish messages:对于域模型发布的每个事件,生成一条消息,其中包含聚合根的完整快照那个时间点,因此实际上只处理 2 种消息 "Create or Update" 和 "Delete"(+元数据,如有必要,提供更具体的信息)
优点
- 幂等(声明性消息表明 "this is what the truth is like, synchronize yourself however you can")
- 消息格式数量减少到 maintain/handle
- 允许逐步纠正消费者的同步错误
- 只要生成的消息遵循规范数据模型,消费者就会自动处理新的领域事件
缺点
- 更大的消息负载
- 少纯
您会推荐一种优于其他方法的方法吗?
我们应该考虑另一种方法吗?
Is there another approach we should consider ?
您还可以考虑不从充当该部分业务technical authority的服务中泄露信息
大致就是说你的事件带有标识符,让感兴趣的人知道感兴趣的实体发生了变化,可以向权威查询状态的更新。
for each event published by the Domain Model, generate a message that contains a full snapshot of the Aggregate Root at that point in time
这还有一个额外的 Con,即对聚合表示的任何更改也意味着对作为 API 一部分的消息架构的更改。因此,聚合的内部变化开始在您的服务边界蔓延开来。如果您正在实施的聚合代表了您的业务的竞争优势,您可能希望能够快速适应;涟漪会增加摩擦,这会减慢你改变的能力。
what if consumer state and producer state get out of sync ?
据我所知,这个问题表明存在设计错误。如果消费者需要状态,也就是说从聚合历史构建的视图,那么它应该从生产者那里获取该视图,而不是试图从观察到的消息集合中 assemble 它。
也就是说,如果需要state,就需要history(complete, ordered)。一个事件真正告诉你的是历史已经改变,你可以驱逐你以前缓存的历史。
同样,对变化的响应:如果你改变了生产者的实现,而消费者也在试图拼凑他们自己的历史副本,那么你的变化就会跨越服务边界。
我们目前正开始将事件从一个中央应用程序广播到其他可能感兴趣的消费者应用程序,我们的团队成员对我们应该在已发布的消息中放入多少有不同的选择.
一般idea/architecture如下:
- 在生产者应用程序中:
- 用户与某些实体(DDD 意义上的聚合根)进行交互,这些实体可以是 created/modified/deleted
- 根据正在发生的事情,引发域事件(例如:EntityXCreated、EntityYDeleted、EntityZTransferred 等......即不仅是 CRUD,而且主要是)
- 引发的事件 translated/converted 到我们发送到 RabbitMQ Exchange 的消息中
- in RabbitMQ (我们正在使用 RabbitMQ,但我认为这个问题实际上与技术无关):
- 我们为每个消费应用程序定义一个队列
- 绑定将交换连接到消费者队列(可能带有消息过滤)
- 在消费应用程序中
- 应用程序使用并处理其队列中的消息
基于Enterprise Integration Patterns,我们正在尝试为我们发布的消息定义规范格式,并且在两种方法之间犹豫不决:
Minimalist messages / event-store-ish :对于域模型发布的每个事件,生成一个仅包含聚合根相关部分的消息(例如,完成更新后,仅发布有关聚合根更新部分的信息,或多或少与最终用户在使用我们的过程时经历的过程相匹配申请)
优点
- 小邮件大小
- 非常专业的消息类型
- 接近"Domain Events"
缺点
- 如果不能保证交付顺序会有问题(即如果在创建消息之前收到更新消息怎么办?)
- 消费者需要知道要订阅哪些消息类型(可能需要一个大列表/领域知识)
- 如果消费者状态和生产者状态不同步怎么办?
- 如何处理未来注册但不了解所有过去事件的新消费者
Fully-contained idempotent-ish messages:对于域模型发布的每个事件,生成一条消息,其中包含聚合根的完整快照那个时间点,因此实际上只处理 2 种消息 "Create or Update" 和 "Delete"(+元数据,如有必要,提供更具体的信息)
优点
- 幂等(声明性消息表明 "this is what the truth is like, synchronize yourself however you can")
- 消息格式数量减少到 maintain/handle
- 允许逐步纠正消费者的同步错误
- 只要生成的消息遵循规范数据模型,消费者就会自动处理新的领域事件
缺点
- 更大的消息负载
- 少纯
您会推荐一种优于其他方法的方法吗?
我们应该考虑另一种方法吗?
Is there another approach we should consider ?
您还可以考虑不从充当该部分业务technical authority的服务中泄露信息
大致就是说你的事件带有标识符,让感兴趣的人知道感兴趣的实体发生了变化,可以向权威查询状态的更新。
for each event published by the Domain Model, generate a message that contains a full snapshot of the Aggregate Root at that point in time
这还有一个额外的 Con,即对聚合表示的任何更改也意味着对作为 API 一部分的消息架构的更改。因此,聚合的内部变化开始在您的服务边界蔓延开来。如果您正在实施的聚合代表了您的业务的竞争优势,您可能希望能够快速适应;涟漪会增加摩擦,这会减慢你改变的能力。
what if consumer state and producer state get out of sync ?
据我所知,这个问题表明存在设计错误。如果消费者需要状态,也就是说从聚合历史构建的视图,那么它应该从生产者那里获取该视图,而不是试图从观察到的消息集合中 assemble 它。
也就是说,如果需要state,就需要history(complete, ordered)。一个事件真正告诉你的是历史已经改变,你可以驱逐你以前缓存的历史。
同样,对变化的响应:如果你改变了生产者的实现,而消费者也在试图拼凑他们自己的历史副本,那么你的变化就会跨越服务边界。