旅程6:我们系统的版本管理 准备下一站:升级和迁移 “变化是生活的调味品。”威廉·考珀
此阶段的最高目标是了解如何升级包含实现CQRS模式和事件源的限界上下文的系统。团队在这一阶段实现的用户场景包括对代码的更改和对数据的更改:更改了一些现有的数据模式并添加了新的数据模式。除了升级系统和迁移数据外,团队还计划在没有停机时间的情况下进行升级和迁移,以便在Microsoft Azure中运行实时系统。
本章的工作术语定义:本章使用了一些术语,我们将在下面进行描述。有关更多细节和可能的替代定义,请参阅参考指南中的“#8e9e8cc60116f64a6bbeee7ef2e51022#”。
Command(命令):命令是要求系统执行更改系统状态的操作。命令是必须服从(执行)的一种指令,例如:MakeSeatReservation。在这个限界上下文中,命令要么来自用户发起请求时的UI,要么来自流程管理器(当流程管理器指示聚合执行某个操作时)。单个接收方处理一个命令。命令总线(command bus)传输命令,然后命令处理程序将这些命令发送到聚合。发送命令是一个没有返回值的异步操作。
事件(Event):一个事件,比如OrderConfirmed,描述了系统中发生的一些事情,通常是一个命令的结果。领域模型中的聚合引发事件。事件也可以来自其他限界上下文。多个订阅者可以处理特定的事件。聚合将事件发布到事件总线。处理程序在事件总线上注册特定类型的事件,然后将事件传递给订阅服务器。在订单和注册限界上下文中,订阅者是流程管理器和读取模型生成器。
幂等性(Idempotency):幂等性是一个操作的特性,这意味着该操作可以多次应用而不改变结果。例如,“将x的值设置为10”的操作是幂等的,而“将x的值加1”的操作不是幂等的。在消息传递环境中,如果消息可以多次传递而不改变结果,则消息是幂等的:这可能是因为消息本身的性质,也可能是因为系统处理消息的方式。
用户故事:在这个过程的这个阶段,团队实现了下面描述的用户故事。
不停机升级V2版本的目标是升级系统,包括任何必要的数据迁移,而不需要把系统停机。如果这在当前实现中不可行,那么停机时间应该最小化,并且应该修改系统,以便在将来支持零停机时间升级(从V3版本开始)。
Beth(业务经理)发言:确保我们能够在不停机的情况下进行升级,这对我们在市场中的信誉至关重要。 显示剩余座位数量
目前,当注册者创建一个订单时,没有显示每种座位类型的剩余座位数量。当注册者选择购买座位时,UI应该显示此信息。
处理不需要付费的座位目前,当注册者选择不需要付费的座位时,UI流仍然会将注册者带到支付页面,即使不需要支付任何费用。系统应该检测什么时候没有支付,并调整流程,让注册者直接进入订单的确认页面。
架构该应用程序旨在部署到Microsoft Azure。在旅程的那个阶段,应用程序由两个角色组成,一个包含ASP.Net MVC Web应用程序的web角色和一个包含消息处理程序和领域对象的工作角色。应用程序在写端和读端都使用Azure SQL DataBase实例进行数据存储。应用程序使用Azure服务总线来提供其消息传递基础设施。下图展示了这个高级体系结构。
在研究和测试解决方案时,可以在本地运行它,可以使用Azure compute emulator,也可以直接运行MVC web应用程序,并运行承载消息处理程序和领域域对象的控制台应用程序。在本地运行应用程序时,可以使用本地SQL Server Express数据库,并使用一个在SQL Server Express数据库实现的简单的消息传递基础设施。
有关运行应用程序的选项的更多信息,请参见附录1“发布说明”。
模式和概念在旅程的这个阶段,团队处理的大多数关键挑战都与如何最好地执行从V1到V2的迁移有关。本节将介绍其中的一些挑战。
处理“事件定义发生更改"的情况当团队检查V2的发布需求,很明显,我们需要改变在订单和注册限界上下文中使用的一些事件来适应一些新特性:RegistrationProcessManager将会改变,当订单有一个不需要付费的座位时系统将提供一个更好的用户体验。
订单和注册限界上下文使用事件源,因此在迁移到V2之后,事件存储将包含旧事件,但将开始保存新事件。当系统事件被重放时,系统必须能正确处理所有的旧事件和新事件。
团队考虑了两种方法来处理系统中的这类更改。
在基础设施中进行事件映射或过滤