azure - 在 CQRS 中实现基于集合的约束

标签 azure cqrs azure-table-storage dddd

我仍在努力解决与 CQRS 风格架构相关的基本(和已解决)问题:

我们如何实现依赖一组聚合根的业务规则?

以预订应用程序为例。它可以帮助您预订音乐会门票、电影座位或餐厅餐 table 。在所有情况下,只会有数量有限的“商品”出售。

假设该事件或地点非常受欢迎。当新事件或时段开始销售时,预订很快就会到达 - 也许每秒有很多。

在查询方面,我们可以大规模扩展,并将预订放入队列中,由自治组件异步处理。首先,当我们从队列中取出预留命令时,我们将接受它们,但在某个时间我们将不得不开始拒绝其余命令

我们如何知道何时达到限制?

对于每个预订命令,我们都必须查询某种商店以确定我们是否可以满足该请求。这意味着我们需要知道当时我们已经收到了多少预订。

但是,如果域存储是非关系数据存储,例如Windows Azure 表存储,我们不能很好地执行 SELECT COUNT(*) FROM ...

一种选择是保留一个单独的聚合根来简单地跟踪当前计数,如下所示:

  • AR:预订(谁?有多少人?)
  • AR:事件/时段/日期(总计)

第二个聚合根将是第一个聚合根的非规范化聚合,但是当底层数据存储不支持事务时,这些很可能在大容量场景中不同步(这就是我们的情况)正在尝试首先解决)。

一种可能的解决方案是序列化预订命令的处理,以便一次只处理一个,但这违背了我们的可扩展性(和冗余)目标。

这样的场景让我想起了标准的“缺货”场景,但不同之处在于我们不能很好地将预订延期交货。事件一旦售完,就已经售完,所以我看不出有什么补偿措施。

我们如何处理这种情况?

最佳答案

经过一段时间的思考,我终于意识到,根本问题与 CQRS 的关系不大,而与不同 REST 服务的非交易性质相关。

归根结底就是这样一个问题:如果你需要更新多个资源,如果第二次写操作失败,如何保证一致性?

假设我们要按顺序向资源 A 和资源 B 写入更新。

  1. 资源 A 已成功更新
  2. 尝试更新资源 B 失败

第一次写操作遇到异常是不容易回滚的,那怎么办呢?捕获并抑制异常以对资源 A 执行补偿操作并不是一个可行的选择。首先,它实现起来很复杂,其次,它也不安全:如果由于网络连接失败而发生第一个异常,会发生什么?在这种情况下,我们也无法针对资源 A 编写补偿操作。

关键在于显式的幂等性。虽然 Windows Azure 队列不保证恰好一次语义,但它们确实保证至少一次语义。这意味着,面对间歇性异常,该消息稍后将重播

在前面的场景中,会发生以下情况:

  1. 尝试更新资源 A。但是,重播会被检测到,因此 A 的状态不会受到影响。但是,“写入”操作成功。
  2. 资源 B 已成功更新。

当所有写入操作都是幂等时,可以通过消息重放来实现最终一致性

关于azure - 在 CQRS 中实现基于集合的约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4355860/

相关文章:

Azure 函数失败并出现 StorageException

azure - Windows Azure 和 Unity3d

azure - 如何在azure移动服务运行时上使用最新版本的nodejs

c# - 哪种数据访问技术最适合 CQRS 查询 Web 服务?

c# - 实现业务规则的规范模式

azure - 是否可以从 Azure 网站访问 Azure 中的表存储

Azure 数据工厂 v2 - SSIS 提升和转移

Azure 文档查询子词典

javascript - 如何从客户端 Angular 处理 CQRS

c# - Azure Durable Function 不创建存储表实体