我正在设计一个CQRS事件源系统(不是我的第一个),其中我的读取模型被非规范化并存储在读取优化文档数据库(MongoDb)中。没什么特别的。现在,这个特定的读取模型是一个文档,其中包含用户ID和用户所属的可能大量的组数组:
{
"userId": 1,
"userName": "aaron",
"groups": [
{
"groupId": 1,
"name": "group 1"
},
{
"groupId": 2,
"name": "group 2"
}
]
}
可能有成千上万的用户中有10个是单个群组的成员(就像一个例子:想象一个每个工作人员所属的群组)。< / p>
请记住我首先使用CQRS的原因是我需要来扩展我的读取(或者更确切地说,考虑到需要避免大量的加入),我期待大量的写入。这不是唯一我使用CQRS和事件源的原因,但它是一个主要的催化剂。
现在我遇到的问题是当有人更新组名时(我预测会经常发生这种情况)我的阅读模型需要更新。这意味着单个用户修改单个数据,将导致我的读取存储中有数千个更新。
我很清楚我可以应用的所有技术来处理调度更新以避免时间耦合,但我关注的是每个用户修改时将更新的文档的 number 。
我已经阅读了几个提出这类问题的SO答案,大多数答案都表明要么需要取得平衡,要么不担心质量更新。但IMO,这不是一个真正的选择。在这种类型的阅读模型中确实没有任何平衡(任何文档的重新建模仍然需要组名出现多次,无论它如何重复-modelled),简单地接受大量的更新对于超快速读取存储的想法是适得其反的,因为它现在将处于严重的负载,因为几乎总是排队的不断更新。基本上会发生什么,是否正规化过程将成为瓶颈,并且队列将随着时间的推移而增长(直到用户更新组名称有一些喘息的机会),并且阅读将变得缓慢作为副作用。
在有人跳过我并问我是否知道这个瓶颈会发生之前,答案就是#34;它应该,但显然我无法确定&#34;。但是,基于知道在我替换的现有系统中进行了多少更改,并且请记住,这不是文档数据库中需要更新的唯一类型的模型,我有很好的理由关注。正如我所说,还有其他几种读取模型 - 可能没有相同数量的更新 - 但仍然会增加读取存储中的写入负载。并且,读取存储只能进行如此多的写入。
我可以想到两种解决方案(一种是愚蠢的,一种不是那么愚蠢):
在每个文档中存储一个版本,然后不更新读取 事件发生时的模型。然后当特定的读取发生时 文件,我检查陈旧性,如果版本是陈旧的(由于 一个进行中的命令),我将最后一个更改应用于该文档 在存储和返回之前。但是,我的直觉告诉了我 最终,无论如何,每个文档都会得到更新 这只是增加了读取的额外开销。我也没有 了解版本控制如何实际工作
使用关系读取模型并进行单个连接。这似乎是 最明智的选择,因为我只是更新连接表,以及所有 很好。但读取的速度并不快,而且只是感觉有点 更不如纯粹的select * from tablename方法。
我的问题:
是否有任何标准技术可以解决此类问题?我提供的第二个选项是我能想到的最好的选择吗?
老实说,我认为这类问题会一直发生在CQRS事件源系统中,其中非规范化数据需要保持同步,但在社区中似乎缺乏对它的讨论这让我相信我错过了一个明显的解决方案,或者我的阅读模型需要改进。
答案 0 :(得分:4)
我认为,当您希望一个用户成为成千上万个群组的成员时,您选择的模型是错误的。您需要从用户文档中删除组列表并坚持关系模型,只保留组ID。想象一下,你的团队需要一些比名字更多的属性,你将再次遇到同样的问题。再一次。