在使用CQRS的事件来源中应如何实施带有条件的搜索

时间:2019-11-04 09:53:33

标签: cqrs event-sourcing

比方说,我需要查询所有符合给定条件的实体。我最大的困惑是应该从哪里获取数据。我猜我们有两个选择,要么查询事件存储本身,要么询问其他投影存储解决方案(不知道-可能是一些数据库或什么)。这可能取决于处理的事件数量。实施效果如何?

  1. 直接询问事件存储区,我们将查询所有实体,然后在应用程序中对其进行过滤?
  2. 使用数据库,我们将只查询基础表,该表将用于特定条件的搜索

那性能呢?。

在事件存储中,最好的办法可能是创建一些快照,无论如何都不确定如何列出复杂的所谓“聚合”。在数据库中,行数与事件数几乎相同,最终将导致数据库的广泛优化。更不用说这个数据库可以随时删除并再次填充,这是我完全无法想象的。我是对的还是对的?

2 个答案:

答案 0 :(得分:0)

事件源:是一种开发应用程序的方式,其中所有信息都作为事件持久化。有关更多信息,请参见here

示例:如果我们正在开发银行软件,则存储的事件将如下所示

  • 用户1,交易次数:100,引用:“ xyz”,日期:2018年10月11日
  • 用户1,事务处理:-100,引用:“ xyza”,日期:2018年10月18日
  • 依此类推...

现在,如果User1要借记他/她的帐户,则我们从他/她的信息流中提取所有事件并重播以获得余额。如果他/她有足够的余额,那么我们会通过添加一个借方事件来借记他/她的帐户。

此过程需要一点时间,并且通常仅在需要写入系统时才执行(在大多数系统中,写入比读取不常见)。尽管这需要花费一些时间,但它为我们带来了审计能力,安全性和运行分析的优势。

事件源系统中的困难在于查询。如果我们需要获取一个季度中存放了10000个单位以上的用户的列表,那么这将是困难且耗时的,因为我们需要重播每个用户流。为了解决这个问题,我们可以使用CQRS。

CQRS:是一种开发软件的模式,其中写入是由一个应用程序完成,而读取是由另一应用程序完成。有更多信息可用here。写入应用程序和读取应用程序可以彼此通信(可以通过消息传递)。读取的应用程序可以维护自己的数据库,并以易于查询的形式存储信息。因此,当读取的应用程序收到消息时,它将转换适合其自己的数据库模式的消息并将其存储。

读取的应用程序最终(可能在几秒钟内)将与写入的应用程序保持一致。读取的应用程序将为其设计数据库模式,因此能够非常快速地快速处理查询。

现在回答您的问题:

  • 在写应用程序中花一些时间来更新数据。写应用程序在任何更新之前都会重放所有事件(或快照后的事件)。只要聚合很小并且我们采用适当的快照技术,性能就不错。
  • 读取模型具有其自己的数据库,该架构旨在适合查询。很多时候,我们不必担心读取数据库中的冗余数据。旨在快速查询。
  • 我们可以决定抛出读取的应用程序(模型)数据并以另一种形状重建它,以适应新的查询,因为事实的来源是存储在写入应用程序(模型)中的事件。

答案 1 :(得分:0)

您还不太了解CQRS。 CQRS的C用于仅更新数据的命令。他们使用事件存储中的事件实例化内存中的实体,进行适当的更改,然后将这些更改存储回事件存储中。此面不适合临时查询。将Command端视为仅允许通过主键访问的数据。

在读取侧,您可以在其中查询具有特定属性的所有实体。读取侧是通过侦听事件存储并在读取侧DB中添加/更新行以使其保持最新状态的特殊代码构建在数据库(不是事件存储)中的。请注意,读取侧数据库不是第三种标准格式–数据经常重复并且外键很少。

因此,虽然从技术上可以查询大多数事件存储区的特定属性,但这很笨拙,因为这不是它们的设计目的。要获取对象的集合,请查询读取端。

介绍一个典型示例

  1. 用户到达您的站点,然后单击一个按钮以查看蓝色T恤的列表。您在读取侧查询Type =“ TShirt”和Color =“ Blue”的所有库存实体,然后将此列表返回到用户屏幕,并带有库存数量的计数器。
  2. 用户单击了一件T恤,因此您可以在读取侧查询有关T恤和图片的详细信息。使用该信息向用户显示该屏幕。
  3. 用户将T恤添加到购物车。您执行AddItemToCart命令,该命令将创建CartCreated事件,然后创建ItemAddedToCart事件,然后创建InventoryDe​​cremented事件。
  4. 读取端正在订阅事件源并看到这些事件,因此它会适当地更新其表。
  5. 第二个用户进来时,他也想要一件蓝色T恤,但是她看到库存已经为0,因为前一个人得到了最后一个。所有这些信息仅来自读取侧数据库,而不来自事件源(命令侧)。

如果您将双方分开,那么如何实现某些事情的许多问题就会消失。