Mongodb 在CQR中处理大量非规范化读取模型更新
我正在设计一个CQRS事件源系统(不是我的第一个),其中我的读取模型被非规范化并存储在一个读取优化文档数据库(MongoDb)中。没什么特别的。现在,这个特定的读取模型是一个文档,它包含一个用户id和一个用户所属的可能较大的组数组:Mongodb 在CQR中处理大量非规范化读取模型更新,mongodb,cqrs,event-sourcing,Mongodb,Cqrs,Event Sourcing,我正在设计一个CQRS事件源系统(不是我的第一个),其中我的读取模型被非规范化并存储在一个读取优化文档数据库(MongoDb)中。没什么特别的。现在,这个特定的读取模型是一个文档,它包含一个用户id和一个用户所属的可能较大的组数组: { "userId": 1, "userName": "aaron", "groups": [ { "groupId": 1, "name": "group 1" }, { "groupId":
{
"userId": 1,
"userName": "aaron",
"groups": [
{
"groupId": 1,
"name": "group 1"
},
{
"groupId": 2,
"name": "group 2"
}
]
}
可能有成千上万的用户是单个组的成员(就像一个例子:想象一个每个工作人员都是其成员的组)
请记住,我首先使用CQR的原因是,我需要扩展我的读取(或者更确切地说,考虑到避免大量连接的需要,以不同的方式处理我的读取),并且我希望有大量的写入。这不是我使用CQR和事件源的唯一原因,但它是一个主要的催化剂
现在我遇到的问题是,当有人更新组名时(我预测这将非常频繁地发生),我的读取模型需要更新。这意味着单个用户对单个数据段的修改将导致我的读取存储中出现10到数千次更新
我很清楚我可以应用的所有技术来处理调度更新以避免时间耦合,但是我关心的是每次用户修改将更新的文档数量
我已经读过一些关于这类问题的答案,大多数答案都表明你要么需要取得平衡,要么不必担心大规模更新。但在国际海事组织,这并不是一个真正的选择。在这种类型的读取模型中真的没有平衡(文档的任何重新建模都需要组名出现,无论它是如何重新建模的,),简单地接受大量的更新与超快速读取存储的想法相反,因为它现在将处于严重的负载下,因为不断的更新几乎总是要排队。从本质上讲,将要发生的是,非规范化过程将成为瓶颈,队列将随着时间的推移而增长(直到用户更新组名有了喘息的机会),并且读取速度将变慢,这是一个副作用
在有人跳到我身上问我是否知道这个瓶颈会发生之前,答案是“应该,但显然我不能确定”。但是,基于知道我要替换的现有系统中进行了多少更改,并且记住,这不是文档数据库中需要更新的唯一模型类型,我有很好的理由担心。正如我所说的,还有其他几种读模型——它们可能没有相同数量的更新——但是会增加读存储中的写负载。而且,读存储只能进行这么多的写操作
我可以想出两个解决方案(一个愚蠢,一个不那么愚蠢):
老实说,我原以为在CQRS事件源系统中,这种类型的问题会一直发生,非规范化的数据需要保持同步,但社区中似乎缺乏对此的讨论,这让我相信我缺少了一个明显的解决方案,或者我的阅读模式需要改进。我认为,当你期望一个用户成为成千上万个组的10个成员时,你选择的模式是错误的。您需要从用户文档中删除组列表,并坚持使用关系模型,只保留组ID。想象一下,您的组将需要比名称更多的属性,您将再次面临同样的问题。再次强调。批量处理导致更新的事件是否有帮助?ie使用拉取模型并拉取所有需要更新读取模型的事件,并一次性完成更新。这样,您就可以有效地让更新过程连续运行,并批量应用更新。只是一个想法…我想如果我批量处理这些更改,并且只播放最新的或适用的更改,这可能会起作用。。。然而,最终的一致性确实被夸大了:)所以您的建议是要么重新设计读取模型,要么在文档数据库中使用关系模型。。。?我认为第一个是唯一有意义的,因为我的阅读模型需要显示组的属性。我认为使用一个必须以某种方式获取每个组属性的读取模型与使用一个用于简化和提高读取性能的读取模型会产生相反的效果。使用一个读取模型并不自动意味着它必须是完全平坦的。我意识到您使用文档数据库的限制,但仍然可以从一组组组ID获取组数据。我喜欢用CQR去规范化模型,但这是一个典型的例子,去规范化很糟糕。我将着眼于改造这个对象