关于dpad的事务问题的分析
最后更新于
这有帮助吗?
最后更新于
这有帮助吗?
针对一致性强弱的要求,制定了如下方案:
一致性要求较强的:
引入Seata,使用XA模式或者AP模式
使用RocketMQ的事务消息机制
有序操作+事务补偿(类Saga模式)
只保证最终一致的,且只要求同时成功:
本地消息表(无mq版本)
类似Saga方案,但是Saga需要服务端:
解决一致性要求较高的场景,比如发起变更、发起终止
不用更改三方服务代码,比如流程服务
每个操作必须是原子的,如果失败,必须立即抛出异常,或返回失败标记
如果发生失败,会从当前事件节点倒序执行事务补偿
下图为Saga的处理方式,内部通过状态机引擎来实现,每个分支事务结束都会进入新的状态、以及产生新的额外的信息:
可能会产生的问题:
事务补偿时出现失败的情况,要怎么处理
为了防止事务补偿失败,所以需要将主事务、分支事务、执行顺序入库到表中,并记录处理状态
当发生补偿失败时,先返回页面状态给前端,并发送钉钉通知
再通过定时任务扫描,对事务重新补偿,再次补偿失败,发送钉钉通知
到达最大重试次数时,发送钉钉通知,手动处理
超过指定次数不再重试
事务补偿失败的情况下,数据是不一致的,这个时候怎么对其他操作做限制约束?
涉及接口做好状态幂等约束,校验关联状态正确才可进行下一步操作
如果状态包含拷贝的情况下,就很难保证幂等校验的有效性了。例如:
发起终止时,同步终止中状态到电站服务,如果后续操作失败,需要回滚状态,回滚出错,这时电站服务的终止状态仍是终止中。
假设电站服务侧有撤销终止操作,且在电站服务,如果使用该状态作为幂等校验就会有问题,实际这笔业务不可进行撤销终止操作。
解决办法:保留一个状态值,以这个状态值为准,或者两个状态值都进行校验。
事务补偿成功,但是事件表状态更新失败的情况怎么处理,怎么避免重复补偿?
如果可以将事件状态更改放入到分支事务的服务中,可以避免事务补偿重复的问题
事件状态的更改属于数据库操作,发生问题的概率较小
补偿操作需要幂等
串行执行效率过慢?
可以设置可并行执行的分支事务,与串行执行事务做区分
提交事务时,可并行执行分支事务,可以同时执行,顺序执行事务只能串行执行
只保持最终一致即可,比如解决审批成功后的数据处理事务问题
定时任务会定时处理插入的事件,并记录事件处理结果
如果事件处理失败,发送钉钉通知,超过指定次数,不再进行重发处理
消息队列可选,如果使用消息队列,吞吐量更高
如果不拆分新的服务并且吞吐量较小,消息队列则不是必须的。
会产生的问题:
其他业务操作可能会需要依赖这个事务提交成功的状态,在不一致窗口时间内,如果保证其他业务的正常?
做好数据幂等校验
增加中间状态,处理中,如果全部处理结束,才是处理成功状态
不增加中间状态,以更改处理成功作为最后一个事务操作,所有事务成功结束才更改状态为处理成功
事件表插入如果不成功,这个事件怎么处理?
先全部插入事件表,让这个操作处于一个数据库事务,如果插入失败,回滚事务,直接返回页面失败状态
事件是否需要进行回滚?
如果事件需要回滚,考虑该种事件方式不合适于你的业务场景。
全局事务表 trans_main
:
id
bigint
true
主键,主事务的id
name
varchar(20)
true
事务名称
main_status
varchar(20)
true
主事务状态
start_time
datetime
true
事务开始时间
end_time
datetime
true
事务结束时间
分支事务表 trans_branch
:
id
bigint
true
主键,分支事务id
main_id
bigint
true
主事务id
branch_name
varchar(20)
true
分支事务名称
branch_status
varchar(20)
true
分支事务状态
exec_order
int
true
分支事务在主事务流程中的位置,从小到大执行
branch_type
varchar(20)
true
分支事务类型(本地事务、接口)
last_start_time
datetime
false
分支事务上次执行时间
end_time
datetime
false
分支事务执行结束时间
retry_count
int
true
分支事务重试次数
exec_commit
text
false
事务提交执行内容
TODO
TODO
变更保存的操作目前可分为两类:
数据库事务:motion、contract、change表的写入
同步变更状态
事务处理方法:
替换声明式事务为编程式事务
将接口放置操作的最后一步
已将接口操作放在最后
数据库事务:contract、change表的写入
同步变更状态
发起审批流
目前有事务问题,且代码执行顺序为 1 3 2。选择的事务处理方法:有序操作+事务补偿。
数据库事务:contract、change表的写入
commit
rollback
同步变更状态
更新变更状态为当前业务的变更状态
更新变更状态为当前业务的上一个变更状态
发起审批流
采用最终一致方案,将审批通过后的操作,细分为如下主事务和分支事务,主事务不受分支事务失败的影响:
主事务:更改决策、变更状态
分支事务1:生成会议纪要和待办任务 (不重试,告警)
分支事务2:生成投资主体待办任务 (不重试,告警)
分支事务3:生成多个土地业务,一个土地业务是一个事务 (重试,告警)
分支事务4:生成多个工程业务,一个工程业务是一个事务 (重试,告警)
分支事务5:为多个工程业务同步电站信息,一个业务作为一个事务
事务5一定要在事务4之后执行。
经过套路,项目只需要保证同时成功的场景即可,不考虑第一种情况,也就是说没有回滚,只保证审批通过后,每个步骤的成功,设计表如下:
将成功后的每个步骤都预先记录到这两张表中,然后按照次序依次开始执行。通用代码已经开发完毕,也已自测,但是在改造时发现投建决策这边改造内容过多,时间不够,原有代码过于混乱,不得不进行代码重构,故终止此需求。
目前每个接口操作在发生错误时,都会发送钉钉报错,以此加人工处理来保证数据一致性。
请参考: