处理分布式事务一致性的方法

1.两阶段提交

首先需要两个载体,一个是事务提交者,一个是协调器。

  1. 第一阶段:

    协调器向所有的事务提交者发起询问,是否可以执行本地事务。

    不同的事务提交者在本地执行事务,执行成功向协调器发送成功,失败则发送失败(超时?)。

  2. 第二阶段:

    协调器如果在第一阶段收到失败,则通知所有事务提交者进行rollback操作。如果没有收到失败则向事务提交者发送可以进行提交。

    事务提交者提交事务,释放资源,并向协调器发送成功,如果是回滚成功,则发送回滚成功。

    协调器收到回信后,结束事务。(未收到回信,例如commit超时)

可以看出来两阶段都有超时问题存在,所以为了增强一致性,一般二阶段提交中会加入结果回查功能。

2.三阶段提交

  1. 第一阶段:

    协调器向所有的事务提交者发起询问,是否可以执行本地事务。

    事务提交者认为可以执行则发送true,不可以则发送false(或者超时)。

  2. 第二阶段:

    如果协调器收到false,则中断事务并发送中断请求,全部收到true,则向事务提交者发送可以准备执行事务的信息。

    事务提交者(未收到或者超时或者收到中断请求,执行事务的中断)收到可以准备执行时,会执行事务操作,

    成功执行会向协调器发送true,失败返回false。

  3. 第三阶段:

    协调器收到二阶段全为true时,向事务提交者发送可以提交,否则发送回滚(未收到或者超时也回滚)。

    事务提交者收到可以提交,提交事务,返回成功(如果超时未收到依然提交事务)。收到回滚,则回滚事务,发送回滚成功。

    协调器收到所有的提交事务成功,结束事务,收到回滚成功,中断事务。

三阶段加入了超时机制,但仍无法完全解决一致性问题,因为在三阶段时,发生超时情况,事务会默认提交。

3.补偿性消息事务

处理分布式事务一致性的方法_第1张图片

在一个分布式场景中,如上图,如果不做任何约束,会产生以下几种情况

  1. 事务A执行报异常

    这时候,事务A执行时出现异常,事务A则会回滚,代码也不会继续执行,对系统无影响。

  2. 事务B执行报异常

    事务B执行报异常,但是事务B属于系统B,回滚事务只会回滚系统B的本地事务,而不会影响到事务A,系统有影响。

  3. 事务A、B执行成功,但是远程调用出现异常

    如果远程调用接口出现异常,该异常发生在系统A中,这时候回滚也只能回滚事务A,而不会影响到事务B,系统有影响,并且最重要的是,无法感知事务B有没有执行

  4. 代码A报异常

    该种情况与上面一种情况相似,不过能够知道事务B执行成功。

能够发现,如果不做额外的工作,碰到异常情况,有75%的概率会发生问题,这也是为什么要引进分布式事务的一个原因。

如果在我们系统中使用2PC、3PC、XA,会严重影响到请求的执行速度,因为2PC和3PC都要等所有事务完成后才会提交全部事务。为了对系统的性能影响降到最小,只能选择容忍一部分系统异常(靠万能的数据订正去解决这些问题),使用基于消息的补偿性事务来解决上面这些问题。

补偿性事务的设计如下图所示

处理分布式事务一致性的方法_第2张图片

事务A的代码执行完以后,就提交事务,提交事务完成后,向消息中心发送一条消息,表明系统A的事务A已经执行成功了,而该条消息的消费方为系统B的事务B。在正常情况下,事务B如果执行成功,会把事务A的消息给消费掉,如果发生了异常情况,这时,消息中心会重推该条消息,直到消息被系统B消息掉,这也就是补偿性的命名,如果事务执行失败了,会不断的补偿直到成功。

明显的,该方案有几个缺陷点

  1. 由于消息会不断重推,就需要事务B的方法做到幂等。

  2. 仍无法解决代码A报异常的情况,但是已经将数据错乱的可能性降低了很多。

  3. 要注意,如果事务A异常回滚了,则不能发送消息,同理,如果发送消息失败了,事务A也要回滚调,最简单的解决方法可以把发送消息放到事务A中。

但是不需要额外的复杂的开发工作,通过一些常用的MQ框架就能很快速的实现。

你可能感兴趣的:(分布式事务,一致性)