【问题标题】:CQRS multi threaded query processingCQRS多线程查询处理
【发布时间】:2018-04-18 05:35:44
【问题描述】:

我们正在构建基于 CQRS 的应用程序。 Command 和 Query 对于大多数信息共享同一个表,但是对于一些重读数据,我们计划有一个单独的查询表以避免多个连接。命令部分将更新其数据然后发布事件,查询部分将监听这些事件并“最终”更新自己的数据。现在的问题/问题是命令部分将在多线程环境中执行,即多个用户将并行处理不同的数据。但是Query部分必须以顺序的方式处理这些事件,因为事件的顺序很重要,所以它不能是多线程的,你可以为不同类型的事件使用不同的线程但只有一个线程可以处理单一类型的事件.在那种情况下,这种架构的规模如何?还是我错过了什么?

【问题讨论】:

    标签: cqrs


    【解决方案1】:

    我们正在构建基于 CQRS 的应用程序。对于大部分信息,Command 和 Query 共享同一个表,但对于一些重读数据,我们计划有一个单独的查询表以避免多个连接。

    所以这个架构不是CQRS,因为分离不完全。为了成为 CQRS,您需要有单独的模型,甚至是数据库/表/集合。

    但是Query部分必须按顺序处理这些事件,因为事件的顺序很重要,所以不能多线程

    让我们谈谈我们可以拥有什么。

    关于事件的排序有两种可能:

    1. 读取模型期望事件是完全有序的;这意味着读取模型的代码希望按照事件生成的顺序处理事件。这意味着事件需要具有某种全局序列号(整数或时间戳,例如 MongoDB 的 Timestamp,每个实例都是唯一的)。

      • 优点:更简单的读取模型代码
      • 缺点:限制写入模型的扩展,因为全局排序需要编写器之间的一些强同步
    2. Read-model 不希望事件按总顺序排列,在单个 Stream 中排序就足够了; Stream 是事件的集合,具有多种类型,由单个实体(如 DDD 中的聚合)生成,并且是有序的。也就是说,Stream 中的事件总是按正确的顺序排列。

      • 优点:架构写入端的可扩展性非常好,写入器(机器、节点)之间没有全局同步
      • 缺点:复杂的读取模型代码,因为它必须重新排序或等待事件,直到它更新其可见数据

    在这两种情况下,读取模型都只使用单一类型的事件。一个读取模型可能会消耗多种类型的事件,而且通常它们会这样做。想象一个 List-of-active-users 读取模型:在一个虚构的用例中,它需要 UserCreatedUserActivatedUserDeleted 事件类型。

    ...因为事件的顺序很重要,所以不能多线程...

    如果您找到可以剪切的维度,它可以是多线程/可缩放的。如果事件类型是由单个实体类型生成的,那么您可以通过实体 ID 拆分读取模型工作人员,例如使用 ID 的哈希;所有工作人员都可以更新 Read-model 的数据库而不会互相踩踏,因为每个工作人员都更新不同的实体。

    在我们虚构的用例中,您可以按 UserId 进行拆分。因此,每个 Read-model worker 都会获得一个它应该处理的 ID 范围。例如,worker 1 开始处理从 1 到 100 的 ID,第二个 worker 开始处理从 101 到 200 的 ID,依此类推。当一个读取模型工作者收到一个事件(通过获取、轮询、发布/订阅等方式)时,它会从中提取用户 ID(即event.getUserId()),如果它与分配的范围不匹配,它就会忽略它。

    在更复杂的情况下,当您需要来自不同实体类型的事件时,您仍然可以扩展。就像上面的例子一样,你只需要找到一个要切割的尺寸。但在这种情况下,会有一些事件类型没有该维度。 这些事件会被所有的worker处理,也就是不会被忽略

    在我们虚构的例子中,当一个事件来自UserAggregate,你被UserId分开,但是当事件来自RoleAggregate(是的,你猜对了,这是一个身份验证和授权有界上下文),它没有UserId 属性,所以它被Read-model 处理,它不会被拒绝。

    所以,这一切都归结为选择一个维度。通常,维度是主要实体的 ID,因为许多读取模型实际上是实体列表,附加了非规范化数据。例如,我们虚构的List-of-active-users Read-model 是一个用户列表,这些用户没有被停用并且还具有与其关联的角色。

    这些模式在某种程度上也可以应用于 Sagas/流程管理器。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多