微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

事件溯源/CQRS 对聚合、原子性、并发性和最终一致性的怀疑

如何解决事件溯源/CQRS 对聚合、原子性、并发性和最终一致性的怀疑

我正在研究事件溯源和命令/查询隔离,我有一些疑问,希望有更多经验的人能轻松回答:

  • A) 一个命令处理程序是否应该使用多个聚合? (也就是他们应该在几个聚合之间协调事情吗?)
  • B) 如果我的命令处理程序生成多个要存储的事件,你们如何将所有这些事件以原子方式推送到事件存储? (我如何保证没有其他命令处理程序会在两者之间“交错”事件?)
  • C) 在我读过的许多文章中,人们建议使用乐观锁定来编写生成的新事件,但在我的用例中,我将有大约 100 个请求/秒。这让我觉得很多请求会以巨大的速度失败(很多 ConcurrencyExceptions),你们是如何处理的?
  • D) 如何处理命令处理程序在将事件存储在事件存储之后但在将它们发布到事件总线之前可能崩溃的事实? (如何最终将那些“已确认”的事件推送回事件总线?)
  • E) 你们如何处理预测中的最终一致性?你只是忍受它吗?或者在某些情况下人们也会把东西锁在那里? (例如等待更新)

我制作了一个序列图来更好地说明所有这些问题

(并且抱歉英语不好)

event sourcing doubts

解决方法

如果我的命令处理程序生成多个要存储的事件,你们如何以原子方式将所有这些事件推送到事件存储?

最合理的事件存储实现将允许您将多个事件批处理到同一个事务中。

在我读到的许多文章中,人们建议使用乐观锁定来编写生成的新事件,但在我的用例中,我将有大约 100 个请求/秒。

如果您有很多并行线程试图维护一个复杂的不变量,那么事情就大错特错了。

对于不希望建立或保持任何不变性的“事件”,那么您只是将内容写入流的末尾。换句话说,您可能不会尝试将事件写入流中的特定位置。所以你可能可以使用批处理来减少冲突写入的数量,以及一个简单的重试机制。实际上,您正在使用与将并发写入器插入队列时出现的相同类型的“扇入”模式。

对于建立/维护不变量的情况,通常不会有很多并发编写器。相反,特定的作者有权编写事件(想想“分片”);那里的并发控制主要是为了避免在异常情况下造成混乱。

如何处理命令处理程序在将事件存储在事件存储中之后但在将它们发布到事件总线之前可能崩溃的事实?

使用拉而非推作为主要订阅机制。确保订阅者可以安全地处理重复消息(又名“幂等”)。当您需要对事件进行严格排序时,不要使用可以重新排序事件的消息订阅。

你们如何处理预测中的最终一致性?你只是忍受它吗?

差不多。视图和报告中包含元数据信息,可让您了解报告在“时间”的哪个固定点是准确的。

除非您在使用报告时锁定所有作者,否则任何数据都有可能过时,无论您使用的是事件还是其他数据模型,无论您是否使用单个数据模型或几个。

这都是权衡的一部分;我们接受报告时间和当前时间之间会有更大的窗口,以换取更低的响应延迟、“不可变”的事件历史等。


一个命令处理程序应该处理多个聚合吗?

可能不会 - 这与永远不会是一回事。

通常的框架是这样的:聚合不像实体那样是域建模模式。这是一种生命周期模式,用于确保我们一次所做的所有更改都是一致的。

如果您发现需要一个命令处理程序同时修改多个域实体,并且这些实体属于不同的聚合,那么您真的选择了正确的聚合边界吗?

有时您可以做的是使用一个命令处理程序来管理多个事务,并在每个事务中更新不同的聚合。但从长远来看,拥有两个不同的命令处理程序可能更容易,每个处理程序都接收命令的副本并独立决定要做什么。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。