分布式最终一致性事务

一、强一致性事务的瓶颈

  在《分布式强一致性事务》一文中介绍了分布式事务的常用协议2PC二阶段提交,虽然2PC能在很大程度上实现分布式事务中各节点的ACID,但也存在同步阻塞问题,协调者单点故障,协调者因网络原因导致的通知不周或收不全参与者回复导致的异常等问题。

  同时,即使能稳定的使用二阶段提交实现分布式事务,但是2PC通信过程中产生的耗时是巨大的,类似淘宝网,下完一个订单后可能需要与计费中心,订单中心,入库,出库等很多子系统打交道,此过程中带来的开销是不能接受的,等到所有流程通知响应完再返回告知用户下单成功,这样的体验也是极差的。

  为此,我们会比较容易想到用MQ来代替这个过程,因为MQ具有异步发起,子操作并行以及解耦子系统的特性,可以极大的提高用户体验。

二、基于MQ的最终一致性

  通过借助MQ队列,处理完业务逻辑后发送消息给消费方,并确保消息是发送成功的,之后消费方消费MQ队列来处理业务逻辑,如果消费并处理成功,则结束,如果没有成功,则重试,直到成功。若重试成功,但业务处理失败,则由人工介入处理(但消费成功,处理失败的场景是极少见的)。

三、实现思路

  通过MQ异步可靠发送,幂等等策略来保证数据的最终一致性,会不可避免的对业务有一定的侵入。

  异步+可靠发送消费思路:

  Producer:需要在业务表所在的库额外建一个消息表,确认表。消息表记录消息发送状态。消息表和业务数据要在一个本地事务里提交。消息表可以比较简单,有消息id,消息对应执行的方法,创建时间,发送状态即可,当业务逻辑执行成功,即向消费方发送消息,并向消息表插入一条消息,状态为已发送。

  Consumer:从MQ队列消费完消息后,处理这个消息,并完成自己的业务逻辑。此时如果本地事务处理成功,那发送给生产方一个confirm消息,Producer会将这条消息插入确认表,状态为已确认,表明整个流程已经处理成功了。如果处理失败,可以考虑发送给Producer一个failed消息,Producer同样会将这条消息插入确认表,只是状态为确认失败。

  重试机制:Producer有一个定时任务,即扫描已发送成功但确认状态为失败的消息,当扫描到有失败的消息时,此时有两个选择, 一是根据这条消息对应的执行方法,去作发送方业务逻辑上的回滚,或通过执行对应的反向sql进行回滚。二是去重发这条失败,即Producer的重试机制,可以设置重试发送的次数,直到消费方确认成功,若到达重试次数仍未有确认成功的状态,则将该消息丢入死信队列,由人工介入重发或进行手工处理。

  注:由于每个节点都可能同时是Producer也是Consumer,所以使用到该方案的服务节点都应该在业务表所在库去创建消息表和确认表。

  幂等机制:在上面的描述中,业务的执行,消息的发送和插入消息表由于在一个本地事务中,所以保证了可靠发送。而消费方处理失败后,有发送方定时重发和私信队列人工处理,也保证了可靠消费(实际生产中,消费方消费后处理业务失败的场景极为少见)。这整个流程保证了可靠发送与可靠消费,但却保证不了一个问题,即消息可能重复发送或重复消费。

  比如定时任务设置的是五分钟,当扫描到一条已发送但未确认的消息时,会进行发送,如果消费方处理时间较长,五分钟内依旧得不到确认成功的答复,则可能扫描到该消息又进行了重发,这样重复发送又可能导致了消费方重复消费,在一个调用过程中,保证消息只被发送一次和只被消费一次,是至关重要的。

  此时引入幂等的概念就极其重要,可以在业务表所在库中增加一张幂等表。如在Producer节点的幂等表记录每条消息的发送次数,保证只能有一次发送,Consumer节点的幂等表记录每条消息的消费次数,保证只能有一次消费,因为每条消息都有一个唯一的消息id,所以可以以消息id来作为判断的依据。

  当Producer产生一条消息时,则将这条消息记录进幂等表,表示该条消息已发送。当消费方返回确认成功时,将消息插入确认表,状态为成功,此时整个流程完结。当返回确认失败时,除了要将消息插入确认表中,状态为失败外,还要将幂等表中该消息id对应的发送记录置为0,方便后面定时器根据发送记录进行重发。若对失败消息的处理选择的是逻辑上的回滚,则可以省去对幂等表的操作。

  当Consumer消费一条消息,并处理完业务逻辑时,则将这条消息记录进幂等表,表示该条消息已消费。当再次消费消息时,可前往幂等表进行判断,存在相同的消息id时,则可以将该消息丢掉,不再重复消费。

  以上描述仅提供参考,对于基于MQ的可靠时间,有许许多多的玩法,例如消费方消费消息,业务处理失败后,也向Producer发送确认成功的消息,自己把这条消息丢自己的死信队列去重试或人工干预,所以一个完整的可靠事件SDK需要提供不同方案对应的不同解决问题的流程。

四、事务消息

    事务消息是一个理想的方案,即消息的发送和消费是自带事务的,即我们只要把消息扔到MQ,那么这个消息肯定会被消费成功。

  生产方不用担心消息发送失败,不用担心消息丢失。而消费方如果消息处理失败了,还有机会继续消费,直到成功为止。

  事务消息可以少去我们很多为了保持一致性而对业务逻辑上的侵入,但遗憾的是市面上大部分MQ中间件都不支持事务消息。

  RocketMQ最新版本已经支持事务消息,但仍需经过时间的考验和成功产品的出现,才能保证基于MQ的最终一致性的春天到来,真正解决分布式事务这一分布式系统中最令人头疼的问题,没有之一。

原文地址:https://www.cnblogs.com/jiyukai/p/9463626.html

时间: 2024-10-11 00:09:17

分布式最终一致性事务的相关文章

分布式事务:两段式提交(最终一致性)

[MySQL如何实现分布式事务?] http://www.linuxidc.com/Linux/2013-10/91925.htm Innodb存储引擎支持XA事务,通过XA事务可以支持分布式事务的实现.分布式事务指的是允许多个独立的事务资源(transac tional resources)参与一个全局的事务中.事务资源通常是关系型数据库系统,也可以是其它类型的资源. 全局事务要求在其中所有参与的事务要么全部提交,要么全部回滚,这对于事务原有的ACID要求又有了提高.另外,在使用分布式事务时候

分布式事务最终一致性常用方案

目前的应用系统,不管是企业级应用还是互联网应用,最终数据的一致性是每个应用系统都要面临的问题,随着分布式的逐渐普及,数据一致性更加艰难,但是也很难有银弹的解决方案,也并不是引入特定的中间件或者特定的开源框架能够解决的,更多的还是看业务场景,根据场景来给出解决方案.根据笔者最近几年的了解,总结了几个点,更多的应用系统在编码的时候,更加关注数据的一致性,这样系统才是健壮的. 一.基础理论 目前关于事务的几大理论包括:ACID事务特性,CAP分布式理论,以及BASE等.ACID在数据库事务中体现,CA

使用MQ来保证分布式事务的最终一致性

前言 之前我们讨论了如何拆分一个订单下单的一个服务(https://www.cnblogs.com/linkstar/p/9610268.html) 从单体到微服务的拆分,当时我们只是对原来的整个服务做了一个简单的拆分,但是在实际中肯定会遇到很多问题,所以我们这里解决一个最容易也是最有可能在实际中遇到的问题,事务. 在单体架构中,我们很容易去维护一个事务,我们想要对一个事务操作回滚也很容易,而在分离成微服务之后,我们想要在多个服务上去维护一个事务就比较困难了.这里我们不再讨论分步事务的实现,转而

MQ关于实现最终一致性分布式事务原理解析

本文讲述阿里云官方文档中关于通过MQ实现分布式事务最终一致性原理 概念介绍 事务消息:消息队列 MQ 提供类似 X/Open XA 的分布式事务功能,通过消息队列 MQ 事务消息能达到分布式事务的最终一致. 半事务消息:暂不能投递的消息,发送方已经成功地将消息发送到了消息队列 MQ 服务端,但是服务端未收到生产者对该消息的二次确认,此时该消息被标记成“暂不能投递”状态,处于该种状态下的消息即半事务消息. 消息回查:由于网络闪断.生产者应用重启等原因,导致某条事务消息的二次确认丢失,消息队列 MQ

分布式服务的事务如何处理?比如dubbo,服务与服务之间的事务怎么处理比较好,现在有没有开源的解决方案?

作者:何明璐链接:http://www.zhihu.com/question/29483490/answer/98237582来源:知乎著作权归作者所有,转载请联系作者获得授权. 首先是不建议采用XA两阶段提交方式去处理分布式事务,要知道要能够支持XA分布式事务,必须是要实现XA规范才可以,而Service本身是无状态的,如果这样去做了等于是把Service内部的东西暴露了出去.对于分布式事务最好的方式还是事务补偿或者BASE基于消息的最终一致性. 可以设想一个最简单的分布式事务场景,对于跨银行

分布式理论(4):Leases 一种解决分布式缓存一致性的高效容错机制(转)

作者:Cary G.Gray and David R. Cheriton 1989 译者:[email protected] 2011-5-7 出处:http://duanple.blog.163.com/blog/static/70971767201141111440789/ [ 序:所谓租约(leases),其实就是一个合同,即服务端给予客户端在一定期限内可以控制修改操作的权力.如果服务端要修改数据,首先要征求拥有这块数据的租约的客户端的同意,之后才可以修改.客户端从服务端读取数据时往往就同

NoSql的三大基石:CAP理论&BASE&最终一致性

关系型数据库的局限 NoSql出现在关系型数据库之后,主要是为了解决关系型数据库的短板,我们先来看看随着软件行业的发展,关系型数据库面临了哪些挑战: 1.高并发 一个最典型的就是电商网站,例如双11,几亿大军的点击造成在某一时刻的并发量是很高的,传统的关系型数据库肯定已经是不堪重负了,如Oracle的Session数量推荐的才只有500. 2.高效率存储海量数据 大数据时代,数据量已经不是用GB.TB来衡量了,而是EB.ZB了,面对这海量的数据,如何高效率的存储这些数据,关系型数据库无法解决这个

分布式系统最终一致性

前言 目前的应用系统,不管是企业级应用还是互联网应用,最终数据的一致性是每个应用系统都要面临的问题,随着分布式的逐渐普及,数据一致性更加艰难,但是也很难有银弹的解决方案,也并不是引入特定的中间件或者特定的开源框架能够解决的,更多的还是看业务场景,根据场景来给出解决方案.根据笔者最近几年的了解,总结了几个点,更多的应用系统在编码的时候,更加关注数据的一致性,这样系统才是健壮的. 基础理论相关 说起事务,目前的几个理论,ACID事务特性,CAP分布式理论,以及BASE等,ACID在数据库事务中体现,

帐务处理最终一致性方案

随着交易量逐步上升,业务越来越复杂,在设计整个帐务处理中考虑最终一致性的方案. 整个方案大概流程可以分为: 在业务完成后同步记录资金变动流水 有的业务场景需要实时处理的账务,则同步发出账务处理的异步消息 通过定时任务每分钟查询需要进行更新帐务的流水记录 启动线程池对每笔流水记录进行帐务更新 在大量数据需要更新的情况下,由于对于处理账务要求非常严格,所以在整个执行过程中需要引入很多技术手段才能达到快速并且正确记账. 和业务执行一起生成最关键的资金变动流水,需要和其他业务绑定在一个事务中,由于这是账