自动的修正一个不正确事件的结果已经可以被处理了.
企业级应用就是要从整个生态中捕获信息,基于那些信息做许多不同的计算,并且在那个生态中发起一些更多的动作. 它们做出的计算和发起的动作只可以跟它们所收到的信息一样精确. 如果你从输入中得到了错误的东西,那你在输出中也会得出错误的东西.
我们已经习惯了这种现象,但是一旦我们在我们的输出中发现了错误,其常常就会是很难处理的. 在大多数情况下,一个人需要去考虑好系统会针对这些错误的输入做些什么,系统会如何反应,系统应该如何反应还有(如果它得到了正确的输入的话),怎样去修正错误的东西.
事件回溯 的诉求之一就是为使得这一繁重的任务更加简单一点提供一个基础. 事实上,对事件和它们的次序的仔细记录,使得人们进行他们的修正活动时简单很多. 追溯事件则进一步是让一个系统可以自动的修正许多错误的结果.
追溯事件建立在 事件回溯 的基础之上, 因此在你可以理解追溯事件之前,你会需要去熟悉事件回溯. 特别是我将要使用我在事件回溯中定义的大量的术语.
其它翻译版本 (1) 加载中要处理一个事件追溯,就意味着我们目前的应用程序状态在某种程度上看来是不正确的. 那样我们在收到事件追溯时,我们将会处在一个同现在所处的状态相比不同的应用程序状态中. 你可以把这当做三个 平行模型 模型来考虑:
不正确的实体: 现有的应用程序运行状态不会被考虑到事件追溯中去.
正确的分支: 我们应该有的应用程序状态会让事件追溯得到处理.
修正的实体: 我们最后想要的应用程序状态.
在许多情况下修正的实体将会同正确的分支一个样 - 那就是我们将对事件日志进行重新处理,来将事件追溯考虑在内. 有时候我们不能完全做到这一点.
我们首先要进行的是就算出不正确的实体在哪个地方,以及正确分支的不同. 事件追溯应该会处理的事件日志中点是很重要的. 我会把这叫做分支点 - 再一次使用了来自时间回溯控制世界中的术语. 分支点是事件日志中追溯事件将会被插入的点之前,最近的点.
有两种我们构建分支点的方法:重建和快退
在追溯事件之前,我们在重建中恢复到应用状态到最后一个快照,那时,我们在前面处理所有的事件,直到我们到达分支点。
在快退/重播中,我们从最新的事件到分支点恢复后面的事件。
我们在并行模型中建立分支点或者我们恢复我们的现场应用程序状态到分支点。如果我们那时恢复我们的实时应用程序状态,当我们前进时,我们自动创建我们正确的分支和纠正现实将是同样的。如果我们使用并发模型,我们在并发模型之中有正确的分支和需要更改实时应用程序状态来把它转换成可纠正的现实状态。基本上在进入直播状态时,合并这个差异。
有三种主要的追溯事件:失序事件,拒绝事件,非正确事件。一个无序事件是逾期收到的,你已经处理的无序事件被接收后你应该处理的事件,但它太迟啦。被拒绝的事件是现在你认识到是假的事件和从来不应该被处理。一个不正确的事件是你收到该事件不正确的信息的事件。
在分支节点之后,三项中的每一项都需要你对事件流作出不同的操纵。
对于乱序(out-of-order)事件,我们在分支节点处插入并处理回溯节点。
对于被抛弃(rejected)事件,我们回退事件并对其作出被抛弃的标记。这样有效地删除了事件日志中的内容。
对于错误(incorrect)事件,我们回退原来的事件并对其作出被抛弃的标记。我们插入回溯事件并处理插入的回溯事件。你可以认为它是一个被抛弃的事件和一个乱序事件的组合体,并被同时处理。
标记为被抛弃的事件在所有后续进处理中都会被忽略掉,所以在将来的重复执行中,这些事件不会再被处理或者回退。他们待在事件日志中来保存历史记录,而且不会被忽略掉。我们不必这样做,我们可以仅仅在原来的事件发生之后立即执行回退操作,但是显然,像那样在每个时间结束后立即进行处理和回退操作效率会较低。
如果错误的事件信息改变了处理顺序,那么错误事件可能会引起更复杂情况。所以我们在4月1号引入了解决办法,然而正确的结果3月1号就已经有了。对于这些情况,我们的分支节点是被抛弃的和正确事件的较早期情况。我们下一步的处理依赖于哪些事件更早。在这个例子中,如果正确事件较早,我们就处理它,并对旧的事件标以被抛弃的标记。然后我们可以继续重复,而旧的事件将被跳过。如果旧的事件是第一个事件,那么我们对它进行回退操作,重复到新的事件,处理它并继续向前处理。
在我们讨论这个的同时,我们还应记住回溯事件本质上是一个事件,这点对于乱序(out-of-order)事件倒没什么影响,不过对于其他的两种情况,影响是巨大的。对于被抛弃(rejected)事件来说,实际上这是在事件日志上删除事件。但是,从根本上来说,我们从不在事件日志上删除事件,所以,我们只是在日志中插入一个被抛弃事件的标记,而被抛弃动作引起了一系列的变化。被抛弃事件实际上是真的被丢弃了,所以它再也不会在重建中被处理。一个错误(incorrect)事件可以被以相同方式来处理,就像一个替换(replacement)事件那样,同时拥有旧的和新的事件。事实上,你可以认为被抛弃(rejected)事件就是一个没有正确事件的替换(replacement)事件。
我确实说过如果你想用你当前的数据来重建并行模型(parallel models),被抛弃和被替换事件都会被丢弃,进而它们也不会被重新运行。但是,如果你正在构建双时态(bi-temporal)并行模型,那你得加入更多的处理,这些处理需要将一些被抛弃事件考虑进来。
在一个并行模型(parallel model)中,如果你遵循组建一个正确分支的风格,你必须预测出正确分支和当前实际情况的差异,并且归并这些差异,来构建被修正的实际情况。
为了发现变化,你需要在以上两种情况中检查所有的对象,从而知道谁发生了改变。同时,你也需要检查仅存在于某一个模型中的所有对象。显然,这可能会是一项庞大的工程,不过你可以通过跟踪哪些对象受到了被处理事件(这些事件从分支点被处理)的影响,来减少工作量。你还可沿着选定的重复运行路线进行分析,从而决定哪些对象子集将会被回溯事件改变。
一旦你找到了变化,那么你就需要将这些变化应用到当前的模型中。在这里,是否将这些变化应用到事件本身上,还是很值得考虑的。你不必非得这样做,因为所有的变化应该能够根据初始事件的分析变得完全可以计算(calculable)。不过,既然这种分析很复杂,那在他们自己的事件中捕获归并变化还是挺有用的。
显然,这种归并处理会变得很混乱,并且当你决定如何处理你的回溯事件时,归并处理的复杂度还是一个很重要的因素,需要认真考虑才对。
因为处理追溯事件和创建一个并行模型非常相似,所以很多优化讨论也适用于这里。反转、快照、选择性重播等技术都可以通过较少的事件处理来帮助你获得分支点。
如果你使用选择性重播来得到分支点,您可以在分支点之后使用相同的选择性重播来向前处理事件。
一个特别有用的使用反转的测试技术,是确保你添加的任何行为在对一个迫使整个要测试的事件序列得以重播的测试案例添加一个追溯事件来进行重放时能工作良好。
另一个测试的想法(虽然我没有直接看到任何例子)是随机生成事件序列,然后用随机的不同顺序来处理它们,以确保它们的结果总是相同的应用程序状态。 a name="UpdatingExternalSystems">
事件源(event sourcing)总是会导致与外部系统不匹配的问题,从而我们无法使用相同的方法进行编译组建。在使用常规事件源进行重新组建时,我们必须保证外部系统不会进行更新。这样相对来说就简单了许多,只需要关闭网关就可以了。不过,如果使用回溯事件来做上面的事,我们就得多做些操作。我们需要判断回溯事件是否对已经升级的内容做了修改,还要明显地处理这些修改。
为了应对这个问题,我们需要两部分操作:探索(detection)和修正(correction)
基本的探索模式是:决定在不正确的状态下,更新的内容应该被送到哪里;决定什么样的更新内容可以送到正确的分支节点处。然后找到任何不同于以上两点的更新内容。
为了解决上面的问题,一种不错的方法是利用网关上的事件源本身,通过将每个外部更新转换成一个事件来处理。如果我们这样做,我们可以在不同模型中捕获这些事件并且将他们进行比对,为了这样做,我们需保证有一种机制来捕获所有的外部事件,并且能够建立两张列表。我们对所有从分支节点发出的更新事件都感兴趣。如果我们采用倒回(rewind)操作,在保证我们能够捕获撤销事件操作发出的更新事件的情况下,我们可以捕获到错误状态更新。
一旦我们获得了错误事实的升级事件清单和正确分支的升级事件清单,我们就能通过比对它们来寻找不匹配的情况。在两份清单中,任何完全相同的升级都可以被忽略掉,我们需要关注的是这类情况:在一张清单上有的事件,在另一张清单上却没有。我们可以建立两张新的事件清单,其中两张清单上的事件不同。这些升级事件需要我们去纠正。
上面的东西都可以按类别来定义,一个类组件可以跟踪事件,并找出两张清单中不匹配的事件。不过,为了处理这些不匹配情况,需要为每个外部系统单独编程,同时还依赖于使用外部系统采用怎样的修补行为。在多数情况下,修正工作无法自动进行,而需要人工来参与整理。不过至少系统可以提供一些信息,这些信息包括什么工作完成了,什么工作应该完成。
[待定TBD(To Be Determined):外部查询(external queries)]
[TBD:一个调节器中的多个事件(multipe events in one adjustment)]
使用事件追溯的主要原因是它常常被用于完成自动输入的修正。正如任何自动化工具一样,你必须频繁且努力去考虑这种修正。如果很多人的时间被花费在做这件事情上,那就值得考虑将类似事件追溯运用到这种自动化上。使用事件追溯的最大优点是,自动化对于它来说是是一个完全通用的处理,一旦你使用事件追溯为任何一个事件工作,之后它就会很方便地扩展到其他事件中去。
我还没有看到事件追溯的普及,因为有一个重要的理由,为了实现事件追溯,你需要准备许多重要的步骤。你需要事件源,如果那还不够,你还需要去添加可逆性(reversibility)或者并行模型。这些都还不是最主要的。因为建立一个应用去支撑事件追溯是一个重大的决定并且对于整个系统会造成影响。对于一个已存在的系统,需要增加必要的代码重构,同时这也是很不容易的。需要去做这种自动化错误修正的,通常不是一个早期的需求,因此,简单地结束一个设计,需要许多工作去做,使事件追溯成为可能。
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。 2KB翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。2KB项目(www.2kb.com,源码交易平台),提供担保交易、源码交易、虚拟商品、在家创业、在线创业、任务交易、网站设计、软件设计、网络兼职、站长交易、域名交易、链接买卖、网站交易、广告买卖、站长培训、建站美工等服务