我最近开始研究CQRS / ES,因为我可能需要在工作中应用它。对于我们来说,这似乎很有希望,因为它将解决很多问题。
我对ES / CQRS应用程序如何看起来像上下文简化后的银行业务用例(提取资金)进行了粗略的了解。
综上所述,如果A人提取了一些钱:
- 发出命令
- 命令已交出以进行验证/验证
- 如果验证成功,则将事件推送到事件存储
- 聚合器使事件出队以对聚合应用修改
据我了解,事件日志是事实的源泉,因为它是FACTS的日志,因此我们可以从中得出任何预测。
现在,在这种宏伟的计划中,我不了解的是在这种情况下会发生什么:
- 规则:余额不能为负
- A人的余额为100e
- 人A发出100e的WithdrawCommand
- 验证通过并发出100e事件的MoneyWithdrewEvent
- 同时,人A发出另一个100e的WithdrawCommand
- 第一个MoneyWithdrewEvent尚未汇总,因此验证通过,因为针对汇总(尚未更新)的验证检查
- 再次发出100e的MoneyWithdrewEvent
==>我们处于不一致状态,余额为-100e,并且日志包含2 MoneyWithdrewEvent
据我了解,有几种策略可以解决此问题:
- a)将聚合版本ID和事件一起放入事件存储中,因此,如果修改后版本不匹配,则不会发生任何事情
- b)使用一些锁定策略,这意味着验证层必须以某种方式创建一个
与策略有关的问题:
- a)在这种情况下,事件日志不再是事实的源头,如何处理?另外,我们还给客户端确定,但是允许退出是完全错误的,在这种情况下使用锁是否更好?
- b)锁==死锁,您对最佳做法有什么见解?
总体而言,我对如何处理并发的理解正确吗?
注意:我了解同一个人不可能在如此短的时间内提取两次资金,但是我举了一个简单的例子,不要迷失细节