• 两阶段提交协议的异常处理


    两阶段提交的协议大家都比較熟悉了,解释一下每一个阶段的异常处理。首先。我们须要持久化协议过程中的状态。这样假设server宕机,那么恢复的时候还能通过日志知道宕机前处于那个阶段。同一时候,全部对数据的改动都会先写write ahead log,保证宕机重新启动的之后数据也不会丢失。写日志的顺序假定为:写write ahead log-改动缓冲区-写commit/abort log。

    在这个前提下,我们依据例如以下的时序图来讨论异常情况和处理方法。

    两阶段提交协议时序

    两阶段提交协议时序

    1. 过程a没有成功,即协调者没有收到部分參与者的回应。超时后。协调者发送abort消息给參与者取消事务。

      參与者存在两种情况:

      • 过程1失败,网络问题导致參与者没有收到vote request消息或者此时參与者宕机。

        參与者重新启动恢复后无需做不论什么事。

      • 过程2失败。參与者收到了vote request。网络问题协调者没有收到回复或此时參与者宕机。

        參与者宕机恢复或等待超时后广播DECISION_REQUEST消息向其它參与者询问是否收到commit/abort消息。

    2. 过程b没有成功。即协调者发送commit消息之后没有收到部分參与者的回应。协调者须要重试,确认參与者的提交完成消息。假设多次尝试不能联系上。则等待參与者上线之后解决。

      參与者存在两种情况:

      • 过程3失败,网络问题导致參与者没有收到commit消息或此时參与者宕机。

        參与者上线发如今本地日志中发现尚未提交成功。由于到达这里。能够肯定本地已做好提交准备,可是不知道协调者是决定提交,所以向协调者询问。按协调者的回复来进行提交或回滚。假设无法联系上协调者,则向其它參与者询问事务状态,假设有某一个节点已经做了提交或异常终止(说明协调者已发送了相关消息)。则做相同的操作。

      • 过程4失败,參与者完毕了commit/rollback。可是网络问题协调者没有收到回应或者此时參与者宕机。參与者在本地日志中发现已完毕本地提交。所以可能由于网络故障导致提交完毕消息没有到达协调者。

        所以直接忽略。

        这时可能协调者在等待该參与者的提交完毕回应消息。所以參与者主动联系协调者告知事务状态。

    3. 过程c没有成功,即參与者发送vote回应消息之后没有等到协调者的commit/rollback消息。这个过程參与者的异常处理已经讨论过了。这里讨论协调者的异常处理。

      存在两种情况:

      • 过程2失败。网络问题导致协调者没有收到回复或此时协调者宕机。协调者恢复重新启动后,发现并未做提交操作,保险操作(由于不知道它是否发送过准备消息。或其它參与者是否做好提交准备),直接发送abort消息给全部參与者,终止事务
      • 过程3失败。网络问题导致參与者没有收到commit/rollback消息或者此时协调者宕机。协调者恢复重新启动后,不能保证全部參与者都已收到了提交消息,所以给全部的參与者发送commit消息,保证事务的正常提交。

    算法的伪代码能够參考例如以下代码。摘自《Distributed Systems: Principles and Paradigms》。

    Actions of Coordinator

    write("START_2PC tolocal log");
    multicast("VOTE_REQUESTto all participants");
    while(not all votes have been collected)
    {
      waitfor("any incoming vote");
      if(timeout)
      {
        write("GLOBAL_ABORT to local host");
        multicast("GLOBAL_ABORT to all participants");
        exit();
      }
      record(vote);
    }
    if(all participants send VOTE_COMMIT and coordinatorvotes COMMIT)
    {
      write("GLOBAL_COMMIT to local log");
      multicast("GLOBAL_COMMIT to all participants");
    }
    else
    {
      write("GLOBAL_ABORT to local log");
      multicast("GLOBAL_ABORT to all participants");
    }
    
    **Actions of Participants**
    
    write("INIT to locallog");
    waitfor("VOTE_REQUESTfrom coordinator");
    if(timeout)
    {
      write("VOTE_ABORT to local log");
      exit();
    }
    if("participantvotes COMMIT")
    {
      write("VOTE_COMMIT to local log");
      send("VOTE_COMMIT to coordinator");
      waitfor("DESCISION from coordinator");
      if(timeout)
      {
        multicast("DECISION_REQUEST to other participants");
        waituntil("DECISION is received"); /// remain blocked
        write("DECISION to local log");
      }
      if(DECISION == "GLOBAL_COMMIT")
      {
        write("GLOBAL_COMMIT to local log");
      }
      else if(DECISION== "GLOBAL_ABORT")
      {
        write("GLOBAL_ABORT to local log");
      }
    }
    else
    {
        write("GLOBAL_ABORT to local log");
        send("GLOBAL_ABORT to coordinator");
    }

    參考文献:

    [1] 两阶段提交(2PC)协议, http://blog.chinaunix.net/uid-20761674-id-75164.html

    原文链接:http://cxh.me/2014/07/07/two-process-commit-exceptions/
  • 相关阅读:
    easyui tree:根据属性格式化树节点名称
    Druid执行多条SQL异常:Cause: java.sql.SQLException: sql injection violation, multi-statement not allow
    springmvc接收jquery提交的数组数据
    jquery easyui:tab自动加载第一个tab内容
    thymeleaf-extras-shiro
    Shiro:授权控制
    thymeleaf : EL1050E The arguments (...) for the constructor call are missing
    (转载)ibatis:解决sql注入问题
    05 Oracle process
    04 memory structure
  • 原文地址:https://www.cnblogs.com/blfshiye/p/5206613.html
Copyright © 2020-2023  润新知