当接收方仍需要更新其读取存储时,CQRS 如何帮助减少锁争用?

How does CQRS help reduce lock contention, when receivers still need to update their read store?

我查看 CQRS 的原因之一是减少我的数据库上的锁争用,因此 写入 只需更新规范化结构,而 reads 可以查找它需要的数据,不受写入竞争的影响。

假设以下设置:

  1. 写入系统写入它自己的规范化数据库 (WriteDb)
  2. 将系统发布消息写入总线以引发事件
  3. 读取系统拾取消息,更新其物化视图(单独ReadDb
  4. 从实体化视图中读取系统读数(ReadDb)

在步骤 3 和 4 中不会仍然存在锁争用吗?读取系统仍然需要更新它的数据副本,这可能与读取同时发生,所以我只是将此视为 减少 锁争用,因为 narrow/less 索引..但危险仍然存在,尽管程度较轻。

有哪些策略可以帮助缓解此问题? (这是一个问题,还是我想多了?)。事件溯源是唯一的方法吗?

注意:我使用的是 .NET / SQL .. 因此,针对该堆栈的任何特定答案都会加分 :)

谢谢

Won't there still be lock contention during step 3 & 4

涉及锁,即使仅在 row/document 级别,但想法是写入发生的频率远低于读取,因此 Write&Read 之间的锁(足够)很少见。

but the danger is still there, albeit to a lesser extent

什么危险?如果你的意思是这会影响阅读速度,那么是的,但是它比 multi-table/multi-join 锁要痛苦得多。

使用 CQRS,您可以(并且应该)创建读取模型(如果您使用的是表 SQL),这些模型对于查询是自给自足的,即您不需要任何连接;这样查询会更快,读锁的概率会更低。

Is Event Sourcing the only way?

事件源不需要使用事务,因此锁比普通 CQRS 更小(更快)——这就是 ES 在读取端更快的原因。

另一种解决方案是使用仅用作读取模型更新的事件源的事件日志(而非事件存储)。一个不便之处是,这是架构的另一个移动部分,它还必须以异步方式(使用线程或其他方式)与写入模型的事件保持同步。

关于使用事件日志的文章:

我不认为 CQRS 从根本上减少了整体锁争用(更不用说消除它了)。正如您所指出的,读取模型仍然需要更新。如果从外部看,read/write 比率并不取决于系统是否使用 CQRS 实现。 (实际的锁争用行为在很大程度上取决于系统实现。)

有人可能会争辩说 CQRS 可以减少写端的锁争用,但对我来说,这本身并不能证明增加的整体系统复杂性是合理的。

据我所知,CQRS 的好处是 1) 允许灵活的读取模型以获得更好的读取性能,更重要的是 2) "stepping stone" 面向事件溯源(正如 Greg Young 在 his DDD Europe 2016 talk).

因此,我认为 "reduced" 锁争用不是决定是否选择 CQRS 的一个因素。

关于事件溯源,再次强调,它并不是对 CQRS 的技术帮助,而是更多的架构动机。