wiki Home
概述
持久任务框架为开发人员提供了一种使用 .NET 任务框架和 .NET 4.5 中添加的 async/await 关键字在 C# 中编写代码协调的方法。
以下是持久任务框架的主要功能:
- 在简单的 C# 代码中定义代码协调
- 程序状态的自动持久化和检查点化
- 协调和活动的版本化
- 异步计时器、协调组合、用户辅助检查点
该框架本身非常轻量级,只需要一个 Azure 服务总线命名空间和可选的 Azure 存储账户。协调和工作节点的运行实例完全由用户托管。用户代码不会在服务总线 “内部” 执行。
问题陈述
许多场景都涉及以事务方式在多个地方更新状态或执行操作。例如,从数据库 A 中的某个账户借入一笔钱,并将其贷记到数据库 B 中的另一个账户中,这些操作都需要以原子方式完成。这种一致性可以通过使用分布式事务来实现,该事务将分别跨越数据库 A 和 B 的借记(debit)和贷记(credit)操作。
但是,为了实现严格的一致性,事务意味着锁,而锁不利于扩展,因为需要相同锁的后续操作会被阻塞,直到锁被释放。对于旨在实现高可用性和一致性的云服务来说,这将成为一个巨大的规模瓶颈。此外,即使我们认为可以承受分布式事务的冲击,我们也会发现几乎没有任何云服务真正支持分布式事务(甚至是简单的锁定)。
实现一致性的另一种模式是在持久工作流中执行借记和贷记的业务逻辑。在这种情况下,工作流的伪代码如下:
- 从数据库 A 中的某个账户借记
- 如果借记成功,则
- 贷记到 DB B 中的某个账户
- 如果上述操作失败,则继续重试,直到达到某个阈值
- 如果贷记仍然失败,则撤销数据库 A 中的借记,并发送通知电子邮件
在理想情况下,这将给我们带来 “最终” 的一致性。也就是说,在(1)之后,整个系统的状态会变得不一致,但在工作流完成后最终会变得一致。然而,在 “不理想” 路径中,有很多事情都可能出错;执行伪代码的节点可能在任意点崩溃,从数据库 A 的借记可能失败,或从数据库 B 的贷记可能失败。在这种情况下,为了保持一致性,我们必须确保以下几点:
- 借记和贷记操作是幂等的,即重新执行相同的借记或贷记操作将变成无操作。
- 如果执行节点崩溃,它将从我们上次成功执行持久操作的地方重新开始(如上文 #1 或 #2a)
从这两项来看,(1) 项只能由借记/贷记活动实现提供。第(2)项也可以通过代码完成,即在某个数据库中跟踪当前位置。但这种状态管理会变得很麻烦,尤其是当持久操作的数量增加时。这时,如果有一个能自动进行状态管理的框架,就能大大简化基于代码构建工作流的过程。