最大努力通知也是一种解决分布式事务的方案,下边是一个是充值的例子:
目标: 发起通知方通过一定的机制最大努力将业务处理结果通知到接收方。
具体包括:
1、有一定的消息重复通知机制。 因为接收通知方可能没有接收到通知,此时要有一定的机制对消息重复通知。
2、消息校对机制。 如果尽最大努力也没有通知到接收方,或者接收方消费消息后要再次消费,此时可由接收方主动向通知方查询消息信息来满足需求。
可靠消息一致性,发起通知方需要保证将消息发出去,并且将消息发到接收通知方,消息的可靠性关键由发起通知方来保证。
最大努力通知,发起通知方尽最大的努力将业务处理结果通知为接收通知方,但是可能消息接收不到,此时需要接收通知方主动调用发起通知方的接口查询业务处理结果,通知的可靠性关键在接收通知方。
可靠消息一致性关注的是交易过程的事务一致,以异步的方式完成交易。
最大努力通知关注的是交易后的通知事务,即将交易结果可靠的通知出去。
可靠消息一致性要解决消息从发出到接收的一致性,即消息发出并且被接收到。
最大努力通知无法保证消息从发出到接收的一致性,只提供消息接收的可靠性机制。可靠机制是,最大努力的将消息通知给接收方,当消息无法被接收方接收时,由接收方主动查询消息(业务处理结果)。
通过对最大努力通知的理解,采用MQ的ack机制就可以实现最大努力通知。
本方案是利用MQ的ack机制由MQ向接收通知方发送通知,流程如下:
本方案也是利用MQ的ack机制,与方案1不同的是应用程序向接收通知方发送通知,如下图:
交互流程如下:
方案1和方案2的不同点:
本实例通过RocketMq中间件实现最大努力通知型分布式事务,模拟充值过程。
本案例有账户系统和充值系统两个微服务,其中账户系统的数据库是bank1数据库,其中有张三账户。充值系统的数据库使用bank1_pay数据库,记录了账户的充值记录。
创建数据库
导入数据库脚本:sql\bank1.sql、资料\sql\bank1_pay.sql,已经导过不用重复导入。
创建bank1库,并导入以下表结构和数据(包含张三账户)
创建bank1_pay库,并导入以下表结构:
启动RocketMQ
rocketmq启动方式与RocketMQ实现可靠消息最终一致性事务中完全一致
discover-server
discover-server是服务注册中心,测试工程将自己注册至discover-server。
导入:资料\基础代码\dtx 父工程,此工程自带了discover-server,discover-server基于Eureka实现。已经导过不用重复导入。
导入dtx-notifymsg-demo
dtx-notifymsg-demo是本方案的测试工程,根据业务需求需要创建两个dtx-notifymsg-demo工程。
(1)导入dtx-notifymsg-demo导入:资料\基础代码\dtx-notifymsg-demo到父工程dtx下。
两个测试工程如下:
dtx/dtx-notifymsg-demo/dtx-notifymsg-demo-bank1 ,操作张三账户,连接数据库bank1
dtx/dtx-notifymsg-demo/dtx-notifymsg-demo-pay,操作李四账户,连接数据库bank1_pay
(2)父工程maven依赖说明
在dtx父工程中指定了SpringBoot和SpringCloud版本
在dtx-notifymsg-demo父工程中指定了
rocketmq-spring-boot-starter的版本。
( 3 ) 配置rocketMQ
在
application-local.propertis中配置rocketMQ nameServer地址及生产组:
rocketmq.producer.group = producer_bank2 rocketmq.name‐server = 127.0.0.1:9876
dtx-notifydemo-pay
dtx-notifydemo-pay实现如下功能:
2)Dao
3)Service
4)Controller
dtx-notifydemo-bank1
dtx-notifydemo-bank1实现如下功能:
1)Dao
2)AccountInfoService
3)监听MQ
4)Controller
测试场景
最大努力通知方案是分布式事务中对一致性要求最低的一种,适用于一些最终一致性时间敏感度低的业务;
最大努力通知方案需要实现如下功能: