分布式系统原理Day07-两阶段提交协议

基本概念

  • 两阶段提交协议是一种经典的强一致性中心化副本控制协议

流程描述

  • 两阶段提交协议是一种典型的 “中心化副本控制协议”
  • 参与的节点分为两类:
    • 一个中心化协调者节点coordinator
    • N个参与者节点participant. 每个参与者节点即为管理数据库副本的节点
  • 两阶段提交的思路:
    • 第一阶段: 协调者询问所有参与者是否可以提交事务,请参与者投票,所有参与者向协调者投票
    • 第二阶段: 协调者根据所有参与者的投票结果做出是否事务可以全局提交的决定,并通知所有的参与者执行该决定
  • 在一个两阶段提交流程中,参与者不能改变自己的投票结果
  • 两阶段提交协议可以全局提交的前提 : 所有参与者都同意提交事务. 只要有一个参与者投票选择放弃abort事务,则事务必须被放弃

两阶段提交协调者流程

  • 写本地日志 “begin_commit”, 并进入WAIT状态
  • 向所有参与者发送后 “prepare消息”
  • 等待并接收参与者发送的对 “prepare消息” 的响应:
    • 如果收到任何一个参与者发送的 “vote-abort消息” :
      • 写本地 “global-abort” 日志,进入ABORT
      • 向所有参与者发送 “global-abort消息”
      • 进入ABORT状态
    • 如果收到所有参与者发送的 “vote-commit消息”:
      • 写本地 “global-commit” 日志,进入COMMIT状态
      • 向所有的参与者发送 “global-commit消息”

两阶段提交参与者流程

  • 写本地日志 “init” 记录,进入INIT状态
  • 等待并接收协调者发送的 “prepare消息”:
    • 如果参与者可以提交本次事务:
      • 写本地日志 “ready”, 进入READY状态
      • 向协调者发送 “vote-commit消息”
      • 等待协调者的消息响应:
        • 如果收到协调者的 “global-abort消息”:
          • 写本地日志 “abort”, 进入ABORT状态
          • 向协调者发送对 “global-abort” 的确认消息
        • 如果收到协调者的 “global-commit消息”:
          • 写本地日志 “commit”, 进入COMMIT状态
          • 向协调者发送对 “global-commit” 的确认消息
    • 如果参与者无法提交本次事务:
      • 写本地日志 “abort”, 进入ABORT状态
      • 向协调者发送 “vote-abort消息”
      • 流程对该参与者结束
      • 如果后续收到协调者的 “global-abort消息” 可以响应
  • 尽管流程结束了,但是在任何时候收到协调者发送的 “global-abort消息” 或者 “global-commit消息” 都要发送一个对应的确认消息

两阶段提交协议宕机恢复

协调者宕机恢复

  • 协调者宕机恢复后,首先通过日志查找到宕机前的状态:
    • 如果日志中最后是 “begin_commit” 记录:
      • 说明宕机前协调者处于WAIT状态
      • 协调者可能已经发送过 “prepare消息”, 也可能没发送过 “prepare消息”. 但是协调者一定还没有发送过 “global-commit消息” 或者 “global-abort消息”
      • 也就是说,事务的全局状态还没有确定
      • 此时,协调者可以重新发送 “prepare消息” 继续两阶段提交流程. 即使参与者已经发送过对 “prepare消息” 的响应,也不过是再次重传之前的响应而不会影响协议的一致性
    • 如果日志中最后是 “global-commit” 或者 “global-abort” 记录:
      • 说明宕机前协调者处于COMMIT或者ABORT状态
      • 此时协调者只需要重新向所有的参与者发送 “global-commit消息” 或者 “global-abort消息” 就可以继续两阶段提交流程

参与者宕机恢复

  • 参与者宕机恢复后,首先通过日志查找到宕机前的状态:
    • 如果日志中最后是 “init” 记录:
      • 说明参与者处置INIT状态,还没有对本次事务做出投票选择
      • 参与者可以继续流程等待协调者发送的 “prepare消息”
    • 如果日志中最后是 “ready” 记录:
      • 说明参与者处于READY状态
      • 说明参与者已经就本次事务做出了投票选择,但是宕机前参与者是否已经向协调者发送 “vote-commit” 消息并不可知
      • 参与者可以向协调者重新发送 “vote-commit”, 并继续协议流程
    • 如果日志中最后是 “commit” 或者 “abort” 记录:
      • 说明参与者已经收到过协调者的 “global-commit消息” 并处于COMMIT状态或者是 “global-abort消息” 并处于ABORT状态
      • 对于是否向协调者发送过对 “global-commit” 或者 “global-abort” 的确认消息则未可知
      • 即使没有发送过确认消息,由于协调者会不断重发 “global-commit” 或者 “global-abort”, 只需要在收到这些消息时发送确认消息即可,不影响协议的全局一致性

两阶段提交协议分析

  • 在工程实践中,很少使用两阶段提交协议,主要原因为:
    • 两阶段提交协议的容错能力差:
      • 两阶段提交协议在某些情况下存在流程无法执行下去的情况,并且也无法判断流程状态
      • 在工程中,良好的分布式协议往往总是可以在即使发生异常的情况下也能执行下去:
        • Lease机制:
          • 一旦Lease发出,无论出现任何异常:
            • Lease服务器节点总是可以通过时间判定出Lease是否有效
            • Lease服务器节点也可以用等待Lease超时的方法收回Lease权限
          • 整个Lease协议的流程不存在任何流程被阻塞而无法执行下去的情况
      • 两阶段提交协议比起Lease协议显得较为复杂并且容错能力差
    • 两阶段提交协议的性能较差:
      • 一次成功提交的两阶段提交协议流程中,协调者与每个参与者之间至少需要2轮交互4个消息:
        • preapre消息
        • vote-commit消息
        • global-commit消息
        • 确认global-commit消息
      • 过多的交互会影响性能
      • 协调者需要等待所有参与者的投票结果,一旦存在较慢的参与者,会影响全局流程执行速度
  • 尽管存在一些改进的两阶段提交协议可以提高容错能力和性能,然而这类协议依旧是在工程中很少使用的一类协议.两阶段提交协议的理论价值大于实践意义

猜你喜欢

转载自blog.csdn.net/JewaveOxford/article/details/107652476