2017-03-02 54 views
1

让我首先说,我没有CQRS的实际经验,这就是这个问题的基础。CQRS和事件源与关系数据库设计结合

背景: 我建立一个系统,一个新的关键要求是允许管理员为“回放”用户操作(管理员希望能够步每一个发生在一个系统中任何特定点的动作) 。需要注意的是,该公司已经有了从当前SQL数据库生成的报表,它们不会更改(至少不会与此新需求并行),因此记录的存储将是SQL。我无法访问SQL的更改数据捕获,因此创建一大堆带触发器的历史记录表将非常难以维护,所以我想尽可能避免这种情况。最后,目前可能(目前还没有)很多数据入口点会经过版本生命周期,导致SQL db的更改(添加/删除字段),所以如果我试图在SQL中实现更改跟踪,我会必须维护处理旧版本数据的表格(噩梦)。

潜在的解决方案 我正在考虑使用的NoSQL(天青DocumentDB)来处理数据存储(写入),然后有命令处理程序处理更新当前SQL(Azure的SQL)的有关数据进行查询(读取) 。通过这种方式创建了审计跟踪,并且可以处理“回放”的想法,同时不会干扰当前提供的后端功能。

这种方法将满足要求并满足注意事项。我不会为整个应用程序使用CQRS,只是为了我需要这种“回放”功能的部分。我知道我必须缓解客户端的故障点 - >写入DocumentDB - >用成功/失败响应用户 - >写入成功的SQL写入DocumentDB路径,但我的新手CQRS的眼睛看不到原因为什么这不是一个很好的方法来处理这个问题。

任何意见将不胜感激。

+1

[Change Feed](https://docs.microsoft.com/en-us/azure/documentdb/documentdb-change-feed)是否允许您侦听更改并将其应用于SQL数据库? –

+0

更改Feed似乎正是我正在寻找的。我认为Dogu的回答更彻底地充实了可以解决我的问题的架构。我将使用ChangeFeed作为“消息队列”和一个监视该队列并相应地处理事务的辅助角色。 – JakeHova

回答

0

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

一旦您定义了您的交易,您需要调整您的工作流程以获得适当的CQRS。客户不是直接向docdb写入数据并等待此调用的结果,而是让客户创建一个具有唯一标识的事务 - 可能类似于Date Time滴答计数或增量事务标识,然后编写此事务到一个像天青队列或服务总线的消息队列。一旦将事务写入队列,就会在此时向用户返回成功。创建工作人员角色,从该队列读取事务消息并处理它们,将对象写入文档数据库。这不会覆盖doc db中的同一个实体,而只是将具有唯一增量id的事务写入该实体的doc db。你也可以使用天蓝色表格存储这个afaik。

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

+0

这对我很有趣。我喜欢你描述的体系结构布局(队列供稿数据存储)。是否有理由在写入DocumentDB之前写入消息队列,而不是直接写入DocumentDB(使用您提到的事务对象)并监视DocumentDB的ChangeFeed队列(建议使用@Matias)来处理事务本身? – JakeHova

+0

确实的队列提供了现成的功能来扩展由工作者角色处理消息,诸如消息可见性等功能,允许安全地处理客户端代码不需要处理的消息。当然,在你的情况下,你的情况下,没有太多的计算,但将实体写入分贝,所以你可以说将这个加载到队列中的好处是微乎其微的 –

0

本文解释了CQRS pattern并提供了一个CQRS实现的例子请参考它。

我想使用的NoSQL(天青DocumentDB)来处理数据存储(写入),然后有命令处理程序处理更新当前SQL(SQL Azure中)与相关数据进行查询(读取)。

这里是我的建议,当用户编写操作来更新记录时,我们总是可以在admin审计用户的操作之前做插入操作。例如,如果用户想更新记录,我们可以插入更新实体,其中包含一个属性,用于指示当前操作是否由管理员审核,而不是直接更新记录。在文件

{ 
    "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数据库。