6

我对范式和相关架构(例如 CQRS)非常陌生。我开始了一个我认为适合这种技术的项目。我发现在项目中使用 EventStore 很有趣,但我在文档中阅读了一些内容,发现使用 EventStore 使得不需要消息总线,因为 EventStore 本身允许订阅事件 - 这是正确的吗?在 EventStore 的顶部实现总线我会有一些优势吗?

4

3 回答 3

7

消息总线和事件存储是两个不同的东西,服务于两个不同的目的。

EventStore (GES) 允许通过使用客户端跟踪或服务器跟踪(竞争消费者)的订阅以及对 ATOM 提要的长轮询来订阅事件。组织成流的事件,每个流都有自己的名称,包含该流的事件。由于 CQRS 和 EventSourcing 通常应用于 DDD 项目,流通常表示聚合,读取单个流允许重新创建聚合状态,并且从流类别(聚合类型)读取事件用于预测(构建读取模型)。每个订阅者控制自己的事件读取过程,并且由于事件被存储,您可以根据需要多次读取它们。

消息总线与保存事件无关。它的目标是在端点之间可靠地传递消息。消息总线通常支持代理或联合拓扑以及不同的模式,如直接发送、发布-订阅和请求-响应。一旦消息消费者确认消息,它就会从队列中删除并且无法再次读取。如果您没有订阅要发布的消息,那么您将永远失去它们。

这意味着,两者都是有用的模式,但事件存储更多地用于持久性和消息总线/代理,以实现持久队列和可靠传递。

于 2016-10-31T20:34:05.843 回答
4

我倾向于这样想,这就是我们设置它的方式:

消息总线:处理命令和事件代理。这用于在各种服务之间进行通信并广播事件。在这种情况下,“事件”是短暂的。它只是供订阅者触发。

EventStore:用于存储对域实体采取的操作。在这种情况下,“事件”是持久的。它的存在是为了重放和获得对象的“状态”。

您不能重播瞬态消息,因为它们只触发一次,然后就被消耗掉了。EventStore 中的事件是持久的/可重放的,并且被重放以获得对象状态或构建投影。一个是经纪人,另一个是来源。

在物理上和概念上在两者之间画一条粗线。

于 2017-09-06T21:40:46.367 回答
3

我看到使用 EventStore 使得没有必要使用消息总线 <snip>...这是正确的吗?

是的,使用事件存储可以使消息总线变得不必要。事件存储是一个持久队列,您可以在其中直接读取事件,在 GES 的情况下,您还可以在事件发生时订阅它们。除了 GES,在其他事件存储中,您可以诉诸数据库轮询以从数据库中获取新消息。(定期发送“自 X 以来的所有消息”的请求。)

消息总线和事件存储之间的主要区别之一是订阅将是“拉”而不是“推”。消息总线确实“推动”它决定您已经看到什么以及您仍然需要什么。我见过的事件存储使用“拉”模型(用于进程外),您可以在其中跟踪自己的检查点。对此有一些小的考虑(定期保存您的检查点),但也有很多功能,您将在下面看到。

注意:GES 确实有推送模型,但它适用于生产者/消费者场景,不会将相同的消息传递到多个端点。

另一个区别是,您通常不能告诉事件总线向您发送以 X 开头的所有消息。即使它具有该功能,取决于 X 多久以前,它可能不再具有这些消息。因此,如果您在代码中发现错误,您可能不得不从一个系统到另一个系统求助于ETL来修复它。错误总是会发生,因此您最终有两种不同的数据传播过程,一种基于事件的快乐路径,另一种基于 ETL 的数据修复。

但是使用事件存储,您可以使用相同的过程来修复快乐路径和数据。所有事件仍然存在(默认情况下,除非另有配置),并且使用拉模型,您可以控制要查看的消息。因此,给定相同的错误,您可以修复代码,然后将受影响的读取模型清空,将其检查点设置为零,然后在重新启动时从头开始重建。无需开发 ETL 流程。(操作问题:如果您的事件存储很大,重建可能需要一些时间,但您可以与旧模型并排创建初始重建,然后在维护窗口中将其交换。)

可以在这里找到一些好的信息/经验。

在其他情况下,总线仍然有意义......例如,当只有最新消息很重要时。或者当有太多消息无法存储时。

在 EventStore 的顶部实现总线的使用会有一些优势吗?

我不这么认为。这种情况下可能有意义的拓扑是让一些代码订阅事件存储并将新消息发布到总线以更新许多侦听器(例如,用于扩展读取)。但是,使用 GES 特定的功能可以更好地解决这种情况。即,使用 AtomPub 和缓存代理的 HTTP API。由于事件是不可变的,在它们被看到一次之后,它们可以被无限期地缓存在每一层。除了第一次发布消息外,这应该避免需要访问事件存储。这仍然允许客户端保留对其自己订阅的控制权。

于 2016-09-15T15:33:26.850 回答