可靠消息最终一致性是解决分布式事务中一种典型的柔性方案。通常有两种实现方式,一种是基于本地消息表,一种是基于RocketMQ的事务消息。需要注意发送消息的一致性和消息的可靠性。
基本原理:
事务发起方执行本地事务成功后发出一条消息,事务参与方也就是消息的消费者,接收到消息并执行成功本地事务。这样来达到数据的最终一致性。
需要注意发起方一定能够将消息发送出去,参与方一定能成功接收到消息。这样来确保消息的可靠性。否则同样会出现分布式事务问题。
本地消息表:
为了防止在使用消息一致性方案时,出现消息丢失,可以使用本地消息表来保证消息的发送。通过本地事务将业务数据和消息写入本地数据库,这一步操作是本地事务可以保证消息表必然会写入数据。然后通过定时任务读物本地消息表中的数据,将消息发送给消息中间件。如果发送失败,进行重试,因此还涉及到幂等操作。消费方接收到消息之后,执行业务(本地事务)成功,则完成分布式事务,若失败则进行重试。如果多次任然失败,则通知事务发起方进行事务回滚。
方案存在如下缺点:
1.消息表耦合在业务库中,需要额外的处理发送消息的操作,不利于消息的扩展,同事如果消息表堆积了大量消息数据,会对业务操作产生一定的性能影响。
2.消息发送失败需要重试,需要保证操作的相关操作的幂等
3.多次重试依然失败需要人工干预
4.消息服务与业务耦合,不利于消息服务的扩展。
RocketMQ事务消息
RocketMQ在4.3版本后引入了完整的事务消息机制,其内部实现了本地消息表的逻辑,使用其事务消息极大的减轻了开发的工作量。
在RocketMQ中,producer和broker具有双向通信能力,使得broker自然的具备了事务协调者的能力。
RocketMQ事务消息分布式事务解决方案原理图:
?roketMQ事务消息案例,官方复制粘贴:
事务消息共有三种状态,提交状态、回滚状态、中间状态:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
|
消息发送的一致性
消息发送的一致性指的事务发起方执行本地事务成功则一定能把其产生的消息发送出去。这里涉及到消息发送与确认机制,消息发送的不可靠性,如何保证消息发送的一致性。
消息发送与确认机制:
常规中间的消息发送与确认机制如下:
1.生产者执行本地事务,然后将消息发送到MQ,这里可以是同步或者异步
2.MQ接收到消息后,将消息数据持久化到磁盘。这个MQ都会提供相应的配置
3.MQ向生产者返回发送结果(消息状态或者异常)
4.消费者监听消费消息
5.消费者执行本地事务
6.消费者向消息MQ确认消费消息
这种流程一般来说无法保证消息发送的一致性。
消息发送如何不一致:
1.先操作数据库,再发送消息。数据库写入了,但消息可能没有发送出去,事务参与方就没有消息可消费
1 2 3 4 |
|
2.先发消息,在操作库。消息发出去,但是本地事务执行失败,参与方可以执行业务,但是发起方没有执行业务
1 2 3 4 |
|
3.同一事务中,先发消息,再操作库。和第二点一样,事务回滚无法控制消息的回滚
1 2 3 4 5 |
|
4.同一事务中,先操作库,再发送消息。这种看似正常,数据保存成功,消息发送失败,事务会回滚。但是如果事务执行成功,消息发送成功,由于网络原因,导致发送消息相应超时,抛出异常回滚了事务,这个时候消息可能已经被事务参与方消费了,并执行了业务。所以还是需要发送确认机制。流程参考上面RocketMQ事务消息流程图
1 2 3 4 5 |
|
消息接收的一致性:
消息接收与确认:
?消息接收的一致性在一定程度上需要满足消息的接收与确认机制:
1.MQ向消费方投递消息
2.消费方收到消息,执行本地事务,执行成功/失败,将结果发送给MQ
3.中间件处理消费者发来的结果,成功则清除消息记录,失败则根据不同的情况处理,比如rabbitMQ,可以设置重回队列
4.MQ投递消息失败会进行重试,多次投递失败,将消息转入死信队列,以便后面人工处理
5.消费方执行完业务,如果如法将结果发送给MQ,同样应该引入重试机制,比如另起线程,扫表数据状态,将结果发送给MQ
需要注意:1.消息接收接口需要保证幂等;2.涉及到重试,最好设置重试次数,以免进入死循环。
消息接收不一致:
1.接收消息的接口没有幂等,如果消息重复投递则会导致数据不一致。
2.消费者可能无法接收消息,此时MQ并没有重试投递,导致事务参与方业务没有执行,引起数据不一致
3.消费者执行完本地业务后,无法将结果反馈给MQ,MQ无法正确的处理消息,进行了重试,消费接口又没有幂等导致数据一不一致
如何保证消息接收的一致性:
1.限制MQ消息投递重试的最大次数
2.消息接收接口保证幂等
3.事务参与方与MQ之间需要确认机制
4.失败的消息转入私信队列,后续人工干预处理