【发布时间】:2015-04-29 17:31:04
【问题描述】:
我正在设计一个 CQRS 事件源系统(不是我的第一个),其中我的读取模型被非规范化并存储在读取优化的文档数据库 (MongoDb) 中。没什么特别的。现在这个特定的读取模型是一个文档,其中包含一个用户 ID 和一个可能很大的用户组数组:
{
"userId": 1,
"userName": "aaron",
"groups": [
{
"groupId": 1,
"name": "group 1"
},
{
"groupId": 2,
"name": "group 2"
}
]
}
可能有成千上万的用户是单个组的成员(仅举一个例子:想象一个每个员工都是成员的组)。
请记住,我首先使用 CQRS 的原因是,我需要扩展我的读取(或者更确切地说,考虑到需要避免大量连接,以不同方式处理我的读取) ,并且我期待大量的写入。这不是我使用 CQRS 和事件溯源的唯一原因,但它是一个主要的催化剂。
现在我遇到的问题是当有人更新组名时(我预测这会经常发生)我的读取模型需要更新。这意味着单个用户对单个数据的修改,将在我的读取存储中导致成千上万的更新。
我很清楚我可以应用的所有技术来处理调度更新以避免时间耦合,但是我关心每个用户修改将更新的文档的数量。
我已经阅读了几个提出此类确切问题的 SO 答案,并且大多数答案表明您需要取得平衡,或者不必担心大规模更新。但是IMO,这不是一个真正的选择。在这种类型的读取模型中确实没有平衡(文档的任何重新建模仍然需要组名出现同样多次,无论它如何重新建模),并且简单地接受大量更新与超快速读取存储的想法适得其反,因为由于几乎总是要排队的不断更新,它现在将承受严重的负载。本质上会发生什么,非规范化过程将成为瓶颈,并且队列将随着时间的推移而增长(直到用户更新组名有一些喘息的机会),并且读取会变慢作为副作用。
在有人跳到我身上问我是否知道会发生这个瓶颈之前,答案是“应该,但显然我不能确定”。但是,基于知道在我要替换的现有系统中进行了多少更改,并且请记住,这不是文档数据库中唯一需要更新的模型类型,我有充分的理由担心.正如我所说,还有其他几种读取模型 - 可能没有相同数量的更新 - 但仍然会增加读取存储中的写入负载。而且,读存储只能接受这么多的写操作。
我能想到两种解决方案(一种笨,一种不太笨):
在每个文档中存储一个版本,并不更新读取 事件发生时的模型。然后当一个特定的读取发生时 文档,我检查过时,如果版本过时(由于 一个正在执行的命令),我将最后一次更改应用于该文档 在存放和退回之前。然而,我的直觉告诉我 最终,无论如何,每个文档都会得到更新,并且 这只是增加了读取的额外开销。我也没有 了解版本控制的实际工作方式
使用关系读取模型并进行单连接。这似乎 最明智的选择,因为我只会更新连接表,以及所有 很好。但是读取不会那么快,只是感觉有点 不如纯粹的 select * from tablename 方法。
我的问题:
是否有解决此类问题的标准技术?我提供的第二个选项是我所希望的最好的吗?
老实说,我本以为此类问题会一直发生在 CQRS 事件源系统中,其中非规范化数据需要保持同步,但社区中似乎缺乏对此的讨论这让我相信我缺少一个明显的解决方案,或者我的读取模型需要改进。
【问题讨论】:
-
批量处理导致更新的事件会有帮助吗?即使用拉取模型并拉取所有需要更新读取模型的事件并一次性完成更新。然后,您可以有效地让更新过程连续运行,批量应用更新。只是一个想法......
-
我想如果我批量更改并且只播放最新或适用的更改,这可能会起作用......但是最终的一致性真的会被夸大:)
标签: mongodb cqrs event-sourcing