【问题标题】:NserviceBus with Azure Service Bus - how to save domain data transactionallyNserviceBus 与 Azure 服务总线 - 如何以事务方式保存域数据
【发布时间】:2017-04-13 11:51:55
【问题描述】:
我想将域事件保存为 DocumentDB 中的文档,然后将该事件发布到 Azure 服务总线 (ASB) 以供其他服务获取。我希望这两个动作在一个事务中,这样如果其中一个失败,另一个会自动回滚。
ASB 为处理程序中的传入和传出(下游)消息提供事务支持,即如果处理程序失败,则不会发送这些消息,并且处理程序中接收到的原始消息不会从总线中删除。但是保存在同一个处理程序中的任何数据呢,比如在我的情况下将事件存储在 DocumentDB 中?如何将其包含在该交易中?
【问题讨论】:
标签:
transactions
nservicebus
azureservicebus
azure-cosmosdb
【解决方案1】:
三个想法:
使整个事务的一侧或另一侧具有幂等性,首先执行另一侧,如果它通过尝试/重试,直到另一侧通过。幂等性意味着您可以多次重做特定事务,并且效果将与您执行一次相同。所以,继续重试,直到它通过。这就是我的服务总线和 DocumentDB 系统的设计方式。
为这些类型的操作从设计中删除服务总线,并使用 DocumentDB 作为您的服务总线。然后确保在对存储过程的一次调用中执行所有您希望被视为单个事务的操作,这将为其提供 ACID 全部通过或全部失败的事务保证。您可能仍然可以将服务总线用于其他事情,但不能用于这些事情。
由于这两个系统是独立的,我能想到的唯一另一种方法是补偿操作。例如,您可以尝试 DocumentDB 端。如果这涉及多个文档或读取然后写入相同的文档,请在存储过程中执行此操作,这将为其提供 ACID 事务保证。确保以您可以撤销它(补偿它)的方式组成交易。如果 DocumentDB 操作没有失败,请尝试服务总线操作。如果失败,则在 DocumentDB 上执行补偿事务。
注意,这第三个选项仍然不是一个完美的解决方案。如果在您尝试服务总线操作期间,在 DocumentDB 端进行了某些操作,导致无法以一致的方式反转该方面,那么您现在将处于不一致的状态。如果它以不可忽视的方式发生,请确保系统抛出一个危险信号。由您来为您的系统建模并确定它的稀有程度。请记住,生活在极其罕见的事件中是可以的。想想 GUID 是如何组成的。仍有可能发生碰撞。它是如此罕见,您无需担心。
即使它不是“非常”罕见,您可能仍然希望这样做,这取决于不一致的罕见程度和破坏性程度。假设,服务总线操作失败的概率是万分之一,补偿事务失败的概率是万分之一。那么这两种情况发生的几率是 1 亿分之一。如果您每月执行 1,000,000 次此类操作,则第一次发生的中位数需要 50 个月,并且它们将相隔大约 100 个月。然后确定它有多糟糕。如果修复其中一个需要花费 10,000 美元(向客户支付违反 SLA 的费用 + 人工修复的人工费用),您能否每 100 个月负担一次这笔费用?
我可能会进一步分析并创建一个蒙蒂卡罗模拟来测试模型中的不确定性。你可能不知道它是否是万分之一的机会,你可能会说,我有 70% 的把握或 90% 的把握它在 1/1,000 和 1/100,000 之间。蒙特卡洛模拟将允许您在该范围内“掷骰子”并生成第一年成本的概率曲线。输出会这样说,“有 10% 的机会在第一年花费我们至少 100,000 美元;有 40% 的机会在第一年花费我们至少 10,000 美元,还有 90%第一年可能会花费我们至少 1,000 美元。
大多数工程师不习惯这样的概率决策,但这就是我的很多写作、演讲和咨询的内容,我已经习惯于帮助工程组织学习以这种方式做出决策,主要是在他们如何建模负载以及他们如何预测特定范围何时完成,但有时我会使用上述模型。结果使团队对他们的决定更有信心。