这是我参与11月更文挑战的第8天,活动详情查看:2021最后一次更文挑战.
参考:《数据库系统概念》19.3,19.4
概念
分布式事务由一个站点发起,多个站点参与。事务必须保证要么在所有站点上都提交,要么在所有站点上都中止。
两阶段提交(Two-Phase Commit,2PC)协议是最简单且使用最广泛的提交协议之一。
考虑一个例子,站点 发起了事务 ,用 来表示各个参与执行事务的站点。
提交协议
当所有 都通知 完成了 的执行时, 启动 协议。
阶段1
- 在稳定存储器上记录日志
<prepare T>,然后给 发送消息prepare T. - 收到消息,确认是否愿意提交。
- 如果选择不提交,就记录日志
<abort T>,然后向 发送消息abort T. - 如果选择提交,就记录日志
<ready T>,并将所有与 相关的日志写入稳定存储器中,然后向 发送消息ready T.
- 如果选择不提交,就记录日志
阶段2
- 如果 收到所有 的
ready T消息,就将日志<commit T>写入稳定存储器中,然后向 发送消息commit T. - 如果 收到至少一个
abort T或者间隔一段时间后没有收到全部消息,就将日志<abort T>写入稳定存储器中,然后向 发送消息abort T. - 当 收到消息后,将消息记录到日志中。
故障处理
和 发生故障有不同的处理方式。
某个站点 故障
的行动
- 如果 在 发送
ready T之前发现 故障,就假定它发送了abort T. - 如果 在 发送
ready T之后发现 故障,就忽略它的故障.
恢复措施
当 从故障中恢复时,检查它的日志以判断应该做什么。
- 日志中存在
<commit T>,此时应执行 . - 日志中存在
<abort T>,此时应执行 . - 日志中仅存在
<ready T>,此时 将 称作疑问事务,应当向 或者其它 询问最终的处理结果。 - 日志中不存在上述三者,此时应执行 。这说明 没有收到来自 的回复。
对疑问事务的处理可能导致一直询问且影响其它事务进行,一个简单的改进是, 在记录 <ready T> 日志时,将 所使用的锁记录下来。等站点恢复后,将这些锁重新申请,这样就不会阻塞与这些锁无关的事务。
故障
当 发生故障时, 通过检查自己或其它 的日志以做出决定。
- 日志中存在
<commit T>,此时应执行 . - 日志中存在
<abort T>,此时应执行 . - 所有 的日志中都是仅存在
<ready T>,此时所有 必须等待 恢复后才能得到答案。如果 持有 上的锁,那么 的其它事务也会收到影响,称作阻塞(blocking)。 - 某些 的日志不存在
<ready T>,说明它们没有向 发送过ready T,此时直接执行 .
评价
的主要缺陷在于协调器故障可能会导致阻塞。
感想
概念基本理解了,想找个成型的代码实例学习一下。
本文也发表于我的 csdn 博客中。