开发人员1:我想谈谈我们应该如何实现与我们CRUD风格的会议管理限界上下文相关联的集成任务的两部分。首先,当业务客户在此限界上下文中为现有会议创建新会议或定义新座位类型时,其他限界上下文中(如订单和注册限界上下文中)需要知道更改。其次,当业务客户更改座位类型的配额时,其他限界上下文也需要知道这种更改。
开发人员2:所以在这两种情况下,您都会从会议管理有限上下文中推送更改。这是一个方法。
开发人员1:是的。
开发人员2:您所说的场景之间有什么显著的区别吗?
开发人员1:在第一个场景中,这些更改相对较少,通常在业务客户创建会议时发生。此外,这些都仅是追加的更改。我们不允许业务客户在会议首次发布后删除会议或座位类型。在第二种场景中,更改可能更频繁,业务客户可能会增加或减少座位配额。
开发人员2:对于这些集成场景,您考虑哪些实现方法?
开发人员1:因为我们有一个两层的CRUD样式的限界上下文,对于第一个场景,我计划将会议和座位类型的信息直接从数据库中公开成一个简单的只读服务。对于第二个场景,我计划在业务客户更新座位配额时发布事件。
开发人员2:为什么这里使用两种不同的方法?使用单一的方法会更简单。从长远来看,使用事件更加灵活。如果其他限界上下文需要此信息,则可以轻松订阅事件。使用事件可以减少限界上下文之间的耦合。
开发人员1:我可以看到,如果我们使用事件,将更容易适应未来不断变化的需求。例如,如果一个新的限界上下文需要知道关于谁更改了配额的信息,我们可以将此信息添加到事件中。对于现有的限界上下文,我们可以添加一个适配器,将新的事件格式转换为旧的。
开发人员2:您的意思是,通知订阅者配额更改的事件发送的是配额的更改。例如,假设业务客户将座位配额增加了50个。这样订阅者如果一开始没有订阅,就不能收到完整的更新历史记录,会发生什么?
开发人员1:我们可以包含一些使用当前状态快照的同步机制。不管怎样,在这种情况下,事件都可以简单的报告配额的新值。如果有必要,事件可以报告座位配额的变化和当前值。
开发人员2:如何确保一致性?您需要确保限界上下文将其数据持久存储并在消息队列上发布事件。
开发人员1:我们可以将数据库写操作和add-to-queue操作封装在一个事务中。
开发人员2:当网络数据的大小增加、响应时间变长和失败的概率增加时,有两个原因会导致以后出现问题。首先,我们的基础设施使用Azure服务总线来处理消息。不能使用单个事务将服务总线上的消息发送和对数据库的写入结合起来。其次,我们试图避免两阶段提交,因为从长远来看,它们总是会导致问题。
领域专家:我们有一个与另一个限界上下文类似的场景,我们将在稍后查看。在这种情况下,我们不能对限界上下文做任何更改,我们不再拥有源代码的最新副本。
开发人员1:我们可以做些什么来避免使用两阶段提交?如果我们不能访问源代码,因此不能做任何更改,我们可以做什么呢?
开发人员2:在这两种情况下,我们使用相同的技术来解决问题。我们可以使用另一个进程来监视数据库,并在它检测到数据库中的更改时发送事件,而不是从应用程序代码中发布事件。这个解决方案可能会引入少量延迟,但是它确实避免了两阶段提交的需要,并且您可以在不更改应用程序代码的情况下实现它。
另一个问题涉及何时何地持久化集成事件。在上面讨论的示例中,会议管理限界上下文发布事件,订单和注册限界上下文处理这些事件并使用它们填充其读模型。如果发生了导致系统丢失读模型数据的故障,那么不保存事件就无法重新创建读模型。
是否需要持久化这些集成事件将取决于应用程序的特定需求和实现。例如:
写端可以处理集成来替代在读端处理,例如:事件将导致写入端发生更改,这些更改将作为其他事件保存。
集成事件可以当做临时数据不做持久化。