Ton*_*pez 6 c# architecture design-patterns cqrs eventstoredb
我对范式和相关架构(例如 CQRS)非常陌生。我开始了一个我认为适合这种技术的项目。我发现在项目中使用 EventStore 很有趣,但我在文档中读了一些,我看到使用 EventStore 使得没有必要拥有消息总线,因为 EventStore 本身允许订阅事件 - 这是正确的吗?在 EventStore 的顶部实现总线会有一些优势吗?
消息总线和事件存储是两种不同的东西,用于两个不同的目的。
EventStore (GES) 允许通过使用订阅(客户端跟踪或服务器跟踪(竞争消费者))以及对 ATOM 提要的长轮询来订阅事件。事件组织成流,每个流都有自己的名字,包含这个流的事件。由于 CQRS 和 EventSourcing 通常应用于 DDD 项目,因此流通常表示聚合,读取单个流允许重新创建聚合状态,从流类别(聚合类型)读取事件用于投影(构建读取模型)。每个订阅者控制自己读取事件的过程,并且由于事件被存储,您可以根据需要多次读取它们。
消息总线与保存事件无关。它的目标是在端点之间可靠地传递消息。消息总线通常支持代理或联合拓扑以及不同的模式,如直接发送、发布-订阅和请求-响应。一旦消息消费者确认了该消息,它就会从队列中移除并且无法再次读取。如果您没有订阅已发布消息的订阅者,您将永远失去它们。
意思是,两者都是有用的模式,但事件存储更多地用于持久性和消息总线/代理用于持久队列和可靠交付。
我发现使用 EventStore 就不需要消息总线 <snip>...这是正确的吗?
是的,使用事件存储可以使消息总线变得不必要。事件存储是一个持久队列,您可以在其中直接读取事件,对于 GES,您还可以在事件发生时订阅事件。除了 GES 之外,在其他事件存储中,您可以借助数据库轮询从数据库中获取进程外的新消息。(定期发送“自 X 以来的所有消息”的请求。)
消息总线和事件存储之间的主要区别之一是订阅将是“拉”而不是“推”。消息总线确实“推送”到它决定您已经看到什么以及您仍然需要什么的地方。我见过的事件存储使用“拉”模型(用于进程外),您可以在其中跟踪自己的检查点。有一些小的会计(定期保存您的检查点),但也有很多功能,如下所示。
注意:GES 确实有推送模型,但它适用于生产者/消费者场景,而不是向多个端点传递相同的消息。
另一个区别是,您通常无法告诉事件总线向您发送所有以 X 开头的消息。即使它具有该功能,根据 X 的时间,它也可能不再有这些消息。因此,如果您发现代码中存在错误,您可能必须借助从一个系统到另一个系统的ETL来修复它。错误总是会发生,因此您最终会使用两种不同的过程来传播数据,一种基于事件以实现顺利路径,另一种基于 ETL 来进行数据修复。
但通过事件存储,您可以使用相同的流程来修复快乐路径和数据。所有事件仍然存在(默认情况下,除非另有配置),并且使用拉模型,您可以控制想要查看的消息。因此,如果遇到相同的错误,您可以修复代码,然后清空受影响的读取模型,将其检查点设置为零,然后重新启动时它将从头开始重建。无需同时开发 ETL 流程。(操作问题:如果您的事件存储很大,重建可能需要一些时间,但您可以与旧模型并排创建初始重建,然后在维护窗口中将其交换。)
可以在这里找到一些好的信息/经验。
总线在其他场景中仍然有意义......例如,当只有最新消息很重要时。或者当消息太多而无法存储时。
在顶部使用总线到 EventStore 会有一些优势吗?
我不这么认为。对于这种情况有意义的拓扑是让一些代码订阅事件存储并将新消息发布到总线以更新许多侦听器(例如用于扩展读取)。然而,使用 GES 特定的功能可以更好地解决这种情况。即,使用 AtomPub 和缓存代理的 HTTP API。由于事件是不可变的,因此在看到它们一次后,它们可以无限期地缓存在每个级别。这应该避免需要访问事件存储,除非第一次发布消息。这仍然允许客户端保留对其自己的订阅的控制。