CQRS 和事件溯源与关系数据库设计相结合

CQRS and Event Sourcing coupled with Relational Database Design

首先让我说,我没有使用 CQRS 的实际经验,这是这个问题的基础。

背景: 我正在构建一个系统,其中一个新的关键要求是允许管理员 "playback" 用户操作(管理员希望能够逐步完成系统中发生的每个操作到任何特定点)。需要注意的是,该公司已经拥有根据当前 SQL 数据库生成的报告,它们不会更改(至少不会与此新要求并行),因此记录的存储将为 SQL.我无权访问 SQL 的更改数据捕获,因此创建一堆带有触发器的历史表将非常难以维护,因此我想尽可能避免这种情况。最后,可能(不是当前)有很多数据入口点会经历版本控制生命周期,这将导致对 SQL 数据库(adding/removing 字段)的更改,因此如果我尝试实施更改跟踪在 SQL 中,我必须维护处理旧版本数据的表(噩梦)。

可能的解决方案 我正在考虑使用 NoSQL (Azure DocumentDB) 来处理数据存储(写入),然后让命令处理程序处理更新当前 SQL (Azure SQL) 的相关数据查询(读取)。这样就可以创建审计跟踪,并且可以处理 "playing back" 的想法,同时也不会干扰所提供的当前后端功能。

这种方法可以满足要求并满足注意事项。我不会将 CQRS 用于整个应用程序,只是用于我需要此 "playback" 功能的部分。我知道我必须减少客户端的故障点 -> 写入 DocumentDB -> 使用 success/fail 响应用户 -> 在成功写入 DocumentDB 路径时写入 SQL,但我的新手 CQRS 眼睛看不出这不是处理此问题的好方法的原因。

如有任何建议,我们将不胜感激。

这篇文章解释了CQRS pattern并提供了一个CQRS实现的例子,请参考。

I am thinking about using NoSQL (Azure DocumentDB) to handle data storage (writes) and then have command handlers handle updating the current SQL (Azure SQL) with the relevant data to be queried (reads).

这里是我的建议,当用户写操作更新记录时,我们总是可以在管理员审计用户操作之前进行插入操作。例如,如果用户想要更新记录,我们可以插入带有 属性 的更新实体,指示当前操作是否由管理员审核,而不是直接更新记录。

文档中的原始数据

{
  "version1_data": {
    "data": {
      "id": "1",
      "name": "jack",
      "age": 28
    },
    "isaudit": true
  }
}

为了更新 age 字段,我们可以插入具有更新信息的实体,而不是直接更新原始数据。

{
  "version1_data": {
    "data": {
      "id": "1",
      "name": "jack",
      "age": 28
    },
    "isaudit": true
  },
  "version2_data": {
    "data": {
      "id": "1",
      "name": "jack",
      "age": 29
    },
    "isaudit": false
  }
} 

然后管理员可以检查当前文档以审核用户的操作并确定更新是否可以写入 SQL 数据库。

一种可能的思考方式是创建一个具有唯一 ID 并表示需要完成的工作的事务对象。这种情况下的事务是将对象写入文档数据库或将对象写入 sql 数据库。它可以包含要写入的内存对象和目标数据库(doc 数据库、sql 等)连接参数。

定义事务后,您需要调整工作流程以获得适当的 CQRS。与其让客户端直接写入 doc db 并等待此调用的结果,不如让客户端创建一个具有唯一 ID 的事务——例如日期时间滴答计数或增量事务 ID,然后写入此事务到消息队列,如 azure 队列或服务总线。一旦您将事务写入队列 return,此时用户就成功了。创建将从该队列读取事务消息并处理它们的工作角色,将对象写入 doc db。这不是覆盖 doc db 中的同一个实体,而是只是将具有唯一增量 id 的事务写入该特定实体的 doc db。您还可以为该 afaik 使用 azure table 存储。

成功更新 doc db 事务后,同一工作者角色可以将此事务写入不同的消息队列,该消息队列将由其自己的一组工作者角色处理,这将更新 sql db 中的实体。如果在此期间出现任何问题,请保留错误 table 并更新该错误 table 中的失败以稍后查询并重试。