事件获取模式
使用仅追加存储到记录完整一系列描述在一个域上取数据,而不是存储仅仅是当前的状态,从而使存储区可以被用来实现该域对象的动作事件。该图案可以通过避免需要同步的数据模型和商业领域中简化复杂的结构域的任务;提高性能,可扩展性和响应能力;提供交易数据的一致性;并保持完整的审计跟踪和记录,可能使补偿措施。
背景和问题
大多数应用程序使用数据,并在典型的方法是应用到通过更新它作为用户使用的数据保持数据的当前状态。例如,在传统的创建,读取,更新和删除(CRUD)模型的典型数据处理将是从存贮器中读出的数据,进行一些修改,以使其和更新的数据的当前状态与新的值时─常常通过使用锁定数据的事务。
CRUD 方法有一定的局限性:
- 在 CRUD 系统直接执行更新操作对数据存储可能会影响性能和响应能力,并限制可扩展性,因为它需要处理开销的事实。
- 在具有许多并发用户的协作域,数据更新冲突更可能发生,因为在更新操作发生在数据的单个项目。
- 除非有另外的审核机制,它记录在一个单独的日志的每个操作的详细内容,历史记录丢失。
注意: 对于的 CRUD 方法的局限性有了更深的了解请参见“CRUD,只有当你能负担得起”MSDN 上。
解决方案
事件获取模式定义了一个方法来处理操作上是受一个事件序列,其中的每一个记录在仅追加存储驱动的数据。应用程序代码发送一系列命令性描述上发生的数据的情况下存储,在那里它们被持久保存的每个动作的事件。每个事件都表示一组数据更改(如 AddedItemToOrder)的。
事件持久保存在一个事件存储在充当真理或记录的系统的源(权威数据源给定的数据元素或信息)有关的数据的当前状态。事件存储通常发布这些事件让消费者能够得到通知,如果需要,可以处理它们。消费者可以,例如,启动该应用中的事件的动作的其他系统的任务或执行完成操作所需的任何其他相关联的动作。注意,生成该事件的应用程序代码从订阅该事件的系统去耦。
在事件存储公布了事件的典型用途是保持实体化视图的应用程序中的行动改变他们,并与外部系统的集成。例如,系统可保持用于填充UI部分的客户订单的实体化视图。随着应用增加了新的订单,增加或订单上删除的项目,并增加了发货信息,描述这些变化可以被处理和使用的事件来更新物化视图。
此外,在任何时间点,可以对应用程序来读取事件的历史,并使用它通过有效地“回放”和消耗所有有关该实体的事件,以实现一个实体的当前状态。这可能发生在需求,以处理时的要求,或通过计划任务,使该实体的状态可以被保存为一个物化视图,以支持表示层来实现域对象。
图1示出的图案的逻辑的概述,包括一些使用事件流,例如,创建的物化视图,与外部应用程序和系统整合事件,并重放事件来创建特定实体的当前状态的突起的选项。
图1 - 的情况下获取模式的概述和示例
事件获取模式提供了许多优点,包括如下:
- 活动是不可变的,因此可以使用仅追加操作来保存。用户界面,工作流或过程发起产生该事件可以继续,并且处理这些事件可以在后台运行的任务的操作。此,结合的事实,有记录的执行过程中没有争用,可以极大地提高性能和可扩展性的应用,尤其是对于表示层或用户界面。
- 活动是描述所发生的一些动作,再加上描述的事件所代表的行动所需的任何相关数据的简单对象。事件不直接更新数据存储;它们被简单地记录用于处理在适当的时间。这些因素可以简化实施和管理。
- 活动通常意味着一个领域的专家,而对象关系的阻抗失配的复杂性可能意味着一个数据库表可能无法清楚地了解该领域的专家。表是表示该系统中,未发生的事件的当前状态,人工构建体。
- 事件的采购可以帮助防止引起冲突,因为它避免了要求直接更新在数据存储对象的并发更新。然而,领域模型仍然必须用来保护自己免受可能导致不一致的状态的请求。
- 事件的仅追加存储提供了可用于监测对一个数据存储所采取的行动的审核跟踪,再生的当前状态作为通过重播事件随时物化视图或预测,并协助测试和调试系统。此外,该规定使用补偿事件取消变化提供了被逆转的变化,这不会是如果模型简单地存储在当前状态的情况下的历史记录。事件列表中,也可以用于分析应用程序的性能,并检测用户行为趋势,或获得其它有用的商业信息。
- 从响应进行操作的事件存储提出的每个事件的任何任务事件的解耦提供了灵活性和可扩展性。例如,用于处理由所述事件存储引发的事件的任务都知道只有事件的性质和它包含的数据。时所执行的任务的方式是从触发事件的动作去耦。此外,多个任务可以处理每个事件。这可能使得与其他服务和系统,只需要监听的事件存储提出了新的事件,易于集成。然而,该事件采购事件往往是非常低的水平,并且可能有必要以产生特异性整合事件来代替。
注意: 事件来源通常结合 CQRS 模式通过执行数据管理任务响应于所述事件,并通过物化从所存储的事件的意见。
问题和注意事项
在决定如何实现这个模式时,请考虑以下几点:
- 创建物化视图或重放事件产生的数据的预测时,系统只会是最终一致。有一个应用程序添加事件,事件存储作为处理一个请求的结果之间有一些延迟,被公布事件,而消费者对事件的处理它们。在此期间,描述该进一步修改实体的新的事件可能已到达的情况下存储。
注意: 请参阅数据一致性底漆有关最终一致性的信息。
- 事件存储是信息不可变源,因此事件数据不应该被更新。要以撤销变更更新一个实体的唯一办法是补偿的事件添加到事件存储,就像你会用负数交易的会计核算。如果持久化事件的格式(而不是数据)需要改变,或者在迁移过程中,可能难以对现有的事件结合在商店的新版本。可能有必要通过所有更改的事件来循环以使它们符合新格式,或添加使用该新格式的新事件。考虑使用上的每个版本的事件模式的版本标记,以保持旧的和新的事件格式。
- 多线程应用程序和应用程序的多个实例可以被存储在事件存储事件。在事件存储事件的一致性是非常重要的,是影响到特定实体(的顺序改变为一个实体发生影响其当前状态)的事件的顺序。添加时间戳到每一个事件是一个选项,可以帮助避免出现问题。另一种常见的做法是将注释每一个事件所导致使用增量标识符的请求。如果两个动作试图为同一实体的同时添加的事件,该事件存储可以拒绝匹配现有实体标识符和事件标识符事件。
- 有没有标准的方法,还是准备建机制,如 SQL 查询,读取事件来获取信息。可以提取的唯一数据是使用事件标识符作为条件的事件流。事件ID通常映射到单个实体。一个实体的当前状态,可以仅通过重放所有涉及到它针对该实体的原始状态的事件的确定。
- 每个事件流的长度可以有上管理并更新该系统的后果。如果流很大,可以考虑创建以特定的间隔的快照,如活动指定数量。可以从该快照,通过重放该时间点之后发生的任何事件中得到的实体的当前状态。
注意: 有关创建数据快照的更多信息,请参见Martin Fowler的企业应用架构的网站和主从快照复制MSDN上的快照。
- 尽管采购活动减少冲突的更新数据的机会,应用程序必须仍然能够应付可能出现的通过最终一致性和缺乏交易的不一致。例如,一个事件,指示库存的库存的减少可能在数据存储到达,而对于该产品的订单被放置,从而导致需求调和这两种业务;可能是建议客户或创建后顺序。
- 事件发布可能是“至少一次”等消费者的事件,必须幂等。它们不能重新在一个事件描述,如果该事件被处理多于一次的更新。例如,如果一消费者的多个实例保持一些实体的一个属性的集合,如订单放置的总数中,只有一个必须在当一个“顺序放置”事件发生时,递增该聚合成功。虽然这不是事件来源的固有特性,它是通常的实现决策。
当使用这个模式
这种模式非常适合以下情况:
- 当你想捕捉“意图”,“目的”或“理”中的数据。例如,如动家,已关闭帐户,或已故变为一个客户实体可被捕捉为一系列特定的事件类型。
- 当它是至关重要的,尽量减少或完全避免更新冲突的发生数据。
- 当你想记录发生的事件,并能够重放它们来恢复系统的状态;用它们来回滚更改的系统;或者简单地作为一个历史和审计日志。例如,当一个任务涉及多个步骤,您可能需要执行恢复更新操作,然后重放一些步骤,使数据恢复到一致状态。
- 当使用事件是应用程序的动作的自然特征,并且需要很少的额外的开发或实现工作。
- 当您需要输入分离或应用这些行动所需的任务更新数据的过程。这可能是为了提高用户界面的性能,或分发事件到其它听众如其他应用程序或服务,必须采取某些行动的事件发生时。一个例子是有费用提交网站整合了工资制度,使响应的费用提交网站做数据的更新提出的事件存储事件由两个网站和工资系统消耗。
- 当您想要的灵活性,能够改变实体化模型和实体数据的格式,如果需求发生变化,或者,当结合使用 CQRS,你需要适应的读模式或公开数据的意见。
- 与 CQRS 一起使用时,和最终一致性是可以接受的,而读出的模型被更新,或者,在从事件流中再水化的实体和数据发生的性能的影响是可以接受的。
这种模式可能不适合于下列情况:
- 小型或简单的领域,很少或没有业务逻辑,或者非域系统,自然与传统的 CRUD 的数据管理机制,运作良好的系统。
- 哪里的一致性和实时更新数据的意见是必需的系统。
- 不要求系统中的审计跟踪,历史,功能,回滚和回放操作。
- 系统中只有非常低的冲突更新到基础数据的发生。例如,主要为添加数据而不是更新它的系统。
例子
的会议管理系统需要跟踪会议完成了预定的数量,以便它可以检查是否有座位仍然可用时,一个潜在的与会者试图做一个新的预订。该系统可以存储预定的总数为在至少两个方面的会议:
- 该系统可以存储关于预约的总数作为数据库中的该搁置预约信息的独立的实体的信息。作为预订制成或取消订单,则系统可以增加或减少该数量适当。这种方法在理论上是简单的,但可引起可扩展性问题,如果有大量的与会者试图进行预订时的短时间内座位。例如,在最后一天或预约期间闭合,以便之前。
- 该系统可以存储大约预订和取消如在事件存储举办的活动信息。然后,它可以计算出可用通过重播这些事件的席位数。这种方法可以更加扩展性由于事件的不变性。该系统只需要能够从事件存储读取数据,或将数据追加到该事件存储。关于预订和取消事件信息不会被修改。
图2显示了如何将会议管理系统的座位子系统可能通过采购活动来实现。
图2 - 使用事件来源获取关于座位预订信息,在会议管理系统
行动预留两个座位的顺序如下:
1.用户界面发出命令,以预留座位有两个人参加。该命令是由一个单独的命令处理程序(一块逻辑的是从用户界面分离,并负责张贴的命令处理请求)处理。 包含所有预订的会议信息
2.一种聚集通过查询描述预订和取消的事件构成。该集合体被称为 SeatAvailability,并且被包含在暴露在聚合查询和修改的数据的方法的域模型。
注意: 一些优化利用快照(这样就不需要查询和重放事件的完整列表,以获得聚集的当前状态),并维持聚合的在存储器中的高速缓存副本来考虑。
3,命令处理程序调用的域模型曝光,使保留的方法。
4.SeatAvailability 骨料记录包含的席位被保留数量的事件。聚合应用事件接下来的时间,所有的预订将被用来计算的座位有多少仍然存在。
5.系统追加了新的事件在事件存储的事件列表。
如果一个用户希望取消一个座位,该系统遵循不同的是,命令处理程序发出,其生成一个座位取消事件,并将其追加到事件存储区中的命令类似的过程
以及可扩展性提供更大的空间,使用事件店内还提供了一个完整的历史,或审计追踪,预订和取消了会议。记录在事件存储在事件真相的权威和唯一来源。没有必要持续聚集体中的任何其他方法,因为该系统可以很容易地重放这些事件和恢复状态,以任意的时间点。