在CQRS“架构”中使用EventStore使得不必使用消息总线?

时间:2016-08-18 11:52:38

标签: c# design-patterns architecture cqrs get-event-store

我对CQRS这样的范例和相关架构都很陌生。我开始了一个项目,我觉得这种技术很合适。我发现在项目中使用EventStore很有意思,但是我在文档中读到了一点,我发现使用EventStore使得没有必要使用消息总线,因为EventStore本身允许订阅事件 - 这是正确的吗?我会在EventStore顶部实现总线吗?

3 个答案:

答案 0 :(得分:3)

消息总线和事件存储是两个不同的目的,用于两个不同的目的。

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

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

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

答案 1 :(得分:2)

  

我看到EventStore的使用使得无需使用消息总线< snip> ...这是正确的吗?

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

消息总线和事件存储之间的主要区别之一是订阅将是" pull"而不是"推"。消息总线会“推送”#34;它决定你所看到的和你仍然需要的东西。我见过的活动商店使用" pull"模型(用于进程外),您可以跟踪自己的检查点。有一些小的会计(定期保存你的检查点),但也有很多权力,你将在下面看到。

注意:GES确实有推送模型,但它适用于生产者/消费者方案,而不是向多个端点传递相同的消息。

另一个不同之处在于,您通常不能告诉事件总线向您发送以X开头的所有消息。即使它具有该功能,根据X的持续时间,它可能不再具有这些消息。因此,如果您发现代码中存在错误,则可能不得不从一个系统求助于ETL来修复它。错误总是会发生,因此您最终会有两个不同的传播数据的过程,一个基于幸福路径的事件,另一个基于ETL进行数据修复。

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

可以找到一些有关信息/经验的here

在其他情况下,总线仍然有意义......例如,只有最新消息才有意义。或者当有太多的消息可以存储时。

  

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

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

答案 2 :(得分:1)

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

消息总线:处理命令和事件代理。这用于与各种服务和广播事件进行通信。 "事件"在这种情况下是暂时的。它只是让订阅者触发。

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

您无法重播瞬态消息,因为它们只会触发一次然后消耗掉它们。 EventStore中的事件是持久的/可重放的,并且会被重放以获得对象状态或构建投影。

在物理和概念上保持两条线之间的粗线。