微服务下的最终一致性解决方案

场景:A服务插入一条记录成功后,调用B服务也插入一条记录,两个操作要同时成功或失败,保持AB服务的事务性

一.设计:

1.增加调用消息服务C,这个服务记录A服务调用B服务的消息,用于存储准执行消息,字段如下:

id:消息id,

param:调用B服务接口的参数

targetUrl:B服务接口地址

uuid:标示这次请求的唯一id,用于判断是否成功执行和幂等,保存在本地执行记录表

checkUrl:A服务验证接口地址,用于验证A服务方法是否成功执行,本地执行记录表中查询uuid,存在即执行了

isOk:标示是否有效需要执行的消息,false表示待执行,true表示可执行

二.调用过程如下:

1.首先A服务的方法设置为本地事务

2.A服务方法先执行插入记录,然后生成uuid插入A本地执行记录表

3.A调用C服务,把uuid,调用B的参数,B的接口地址,校验A是否执行的checkUrl,isOk为false,插入消息表

(备注:这里A服务可以先写入mq,C服务消费mq,这样就是异步的,算是性能优化)

4.插入失败,则throw异常,回滚A服务,如果插入成功则A服务事务成功执行

(备注:可能C服务执行成功,返回的超时异常,造成A服务回滚,这样A没执行,C却记录了消息,这里不用担心)

5.定时任务扫描C服务的消息表isOk为false的,以uuid为参数调用checkUrl地址,去查询A的本地执行表是否有uuid,如果有则说明A成功执行,此C服务消息可执行,设置isOk为true,如果没有查询到uuid,则说明A执行失败,则将此C服务消息记录删除

(备注:此任务命名为:待执行定时任务)

6.定时任务扫描C服务的消息表isOk为true的,以param和uuid为参数,targetUrl为接口地址,调用B服务接口,成功则删除此记录,失败则下次扫描继续调用直到成功

(备注:此任务命名为:可执行定时任务,

这里可以先把C服务扫描的isOk为true的记录写入mq,然后B服务消费mq,这样就是异步的,算是性能优化)

7.B服务接口要设置为本地事务,先用uuid查询B服务的本地执行记录表,如果存在此uuid,说明已经执行过了,直接返回成功;如果没查询到,就将uuid写入B服务本地执行记录表,再执行B服务逻辑

三.说明

这种情况的前提是A服务执行后B服务业务上一定能执行成功,而无需做资源预留的情况

如果你的情况是A执行成功后,B不一定能成功,那么第6步就会无限循环去调用B服务,一直失败

此文只是自己的设计思路,没有实践过

发布了42 篇原创文章 · 获赞 25 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/qq812858143/article/details/94720052