200字范文,内容丰富有趣,生活中的好帮手!
200字范文 > sybase 事务 超时返回_分布式事务设计与实践-消息最终一致性

sybase 事务 超时返回_分布式事务设计与实践-消息最终一致性

时间:2020-06-02 14:07:58

相关推荐

sybase 事务 超时返回_分布式事务设计与实践-消息最终一致性

消息最终一致性方案产生背景

在前面的文章我们分析过2PC,TCC和Saga,其实我们可以发现这些方案都适用于同步调用的一些业务场景。在微服务架构中,我们一个业务功能可能涉及多个服务之间的调用,调用链路非常长,这时我们通常采用非核心业务异步调用来优化调用链路(异步调用)。(题外话:TCC,Saga实现方案)

拿下单场景来分析下:

同步调用:用户请求下单 -> 订单服务进行下单操作 -> 调用支付服务生成一笔待支付记录异步调用:用户请求下单 -> 订单服务进行下单操作 -> 往MQ投递一条下单消息 -> 返回用户下单成功 -> 支付服务异步消费下单消息,生成待支付记录

同步调用场景我们可以使用TCC和Saga来保证事务一致性,那异步调用场景我们又要如何来保证一致性呢?消息最终一致性方案就是用于解决这个问题。

传统消息处理方式

实现方式一:

public void processOrder() {// 订单处理(业务操作) orderService.process();// 发送订单处理成功消息(发送消息) sendBizMsg ();}

存在问题:投递消息后响应超时异常,这时无法知道消息是否投递成功,从而不知道是否需要回滚订单处理数据库操作。

有人提出方案,响应超时之后去查询消息系统,确认这条消息是否投递成功?这个方案是否可行?如果这时消息系统挂了,确认消息是否投递成功这个查询操作就会一直超时,这时就也没法确认消息是否投递成功。

实现方式二:

@Transactionnalpublic void processOrder() {try{// 订单处理(业务操作) orderService.process(); // 发送订单处理成功消息(发送消息) sendBizMsg ();}catch(Exception e){事务回滚; }}

我们来分析下这个方式是否能保证一致性,消息发送的异常情况分析

通过分析,上述的两种方式都无法保证一致性,根本原因在于:发送消息这个远程调用,结果可能为超时,超时这种情况消息有可能是投递 成功了,也可能是投递失败了,调用方式无法知晓的。

事务消息实现思路

RoekctMQ事务消息通过异步确保方式,保证事务的最终一致性。设计流程上借鉴两阶段提交理论。

过程:

1.应用服务遇到发送事务消息的场景时,先发送half消息给MQ Server。

2.half消息发送成功后,应用服务执行本地事务。

3.根据数据库事务执行的结果,业务服务对MQ Server发送Commit或者Rollback请求。

4.MQ Server接收到Commit请求,把消息下发给Comsumer,如果是Rollback,直接删掉half消息。

5.如果MQ Server一直没有收到4步骤的commit或者Rollback答应,定时任务主动回查业务服务事务状态(最多重试15次,超过了默认丢弃消息),处理结果同第4步。

6.MQ消费的成功机制由MQ自己保证。

RocketMQ事务消息实现流程

以RocketMQ 4.5.2版本为例,事务消息有专门的一个队列RMQ_SYS_TRANS_HALF_TOPIC,所有的prepare消息都先往这里放,当消息收到Commit请求后,就把消息再塞到真实的Topic队列里,供Consumer消费,同时向RMQ_SYS_TRANS_OP_HALF_TOPIC塞一条消息。简易流程图如下:

这个方案的缺陷是:

1.需要消息中间件支持事务消息功能。(RocketMQ 4.3.0版本以后开始支持事务消息)

2.业务方需要提供一个回查接口,用于MQ Server确认Commit或者Rollback结果。

基于本地消息的最终一致性

实现过程:

1.业务调用方创建一张本地消息表。业务操作成功后,本地消息表插入一条消息记录,这两个操作绑定在一个本地数据库事务中。

2.定时任务异步扫描本地消息表,查询到待发送消息记录时,往MQ Server发送一条消息。

3.投递消息后,MQ Server返回成功ACK,将本地事务表这条记录改为已发送状态。

4.业务被调用方消费到消息后,执行本地业务操作,返回消费成功ACK给MQ Server。

5.如果MQ Server一直没有收到消费方返回的成功ACK,会一直进行消息投递操作,所以消费方的业务操作必须要保证幂等性。如果消费者执行业务失败了,记录失败日志、告警、人工介入。

该方案最核心做法就是在执行业务操作的时候,记录一条消息数据到DB,并且消息数据的记录与业务数据的记录必须在同一个事务内完成,这是该方案的前提核心保障。

独立消息服务的最终一致性

实现过程:

1.服务调用方请求消息服务系统,往消息表保存一条预发送消息。

2.消息服务系统响应预发送消息保存成功,服务调用方开始执行业务逻辑。预发送消息保存失败,服务调用方则不会再执行业务逻辑。

3.服务调用方执行完本地业务逻辑,请求消息服务系统,告知它业务逻辑执行结果,业务逻辑执行成功则预发送消息更新为“可发送”状态,业务逻辑执行失败则预发送消息更新为“不可发送”状态。

4.如果消息服务系统一直没有收到业务逻辑的执行结果,则预发送消息一直为“待发送状态”,这时会启个定时任务1去调用服务调用者的查询接口,确认“待发送”消息是否可以发送。

5.定时任务2查询状态为“可发送”状态的记录,请求MQ Server发送消息,MQ Server返回成功ack则把消息记录改为“已发送”状态。

6.后面的消费流程则跟上文本地事务方案一致。

该方案的优点是:

1.不用在业务方创建本地消息表,消息表的维护和消息的发送由消息服务统一管理。

总结:

消息最终一致性方案适用于异步调用场景。事务消息:需要消息中间件支持事务消息特性,核心是消息发送进行两阶段提交,业务方提供一个回查接口给MQ Server进行状态确认。本地消息最终一致性:将消息表插入记录与业务逻辑执行绑定在同一个本地事务中,通过异步定时任务和MQ的ACK确认机制来确保消息的发送和消费成功,消息消费后无法执行回滚操作,这时可以采用人工介入的方案。独立消息服务最终一致性:实现思想跟事务消息很相似,通过两阶段提交来确保消息发送和本地事务的一致性,整体实现复杂度较高。

参考资料:

/apache/rocketmq/blob/master/docs/cn/features.md​MQ消息最终一致性解决方案​/nam.html​

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。