首页 > 其他分享 >【分布式】优雅实现多系统一致性补偿方案

【分布式】优雅实现多系统一致性补偿方案

时间:2025-01-09 18:34:11浏览次数:1  
标签:COMMENT 事务 BPM 系统 优雅 任务 一致性 NULL 分布式

前言

我们在开发的过程中,如果一个业务操作需要本地写MYSQL数据以及对第三方系统做写操作,那么这种流程就涉及到分布式系统一致性的问题,然而并非所有系统都能使用成熟的分布式事务方案

案例说明

以一个财务报账业务为例,涉及到的系统如下:

系统名 作用 实现方案
单据系统 申请单内容以及凭证的生成 JAVA
BPM 实现流程的运转 购买成熟系统(例如:泛微)
SAP 财务凭证 购买成熟系统

详细解释下各系统作用:

单据系统:财务报账,会提交很多信息(例如:报账事由、报账金额与明细)。同时也会生成财务凭证(不了解凭证也没关系,它就是给财务人员看的东西,对技术人员来说就是数据库的一堆数据)

BPM系统:非常成熟的流程管理系统,以非常直观的方式来实现流程的搭配,不了解的可以自行百度扫盲。在此案例中,需要使用BPM的两个能力:1)调用API,审核通过 2)调用API,获取流程的待审人

SAP系统:财务专用系统,不用过多了解,只要知道在财务审核完成后,会将单据系统生成的凭证数据通过API调用的方式发送给SAP即可

“审核通过”业务流程

当审核人员审核通过时,大致流程如下:

  • 保存业务数据+记录审核日志
    
  • 调用BPM接口,审核通过
    
  • 调用BPM接口,获取最新待审人
    
  • 如果没有待审人,说明已经审完,生成凭证并推送SAP
    

代码如下

风险分析

如图所示,如果在1和2出现异常,由于有事务的存在,操作1内的几条mysql写操作会被回滚,因此所有数据都没有任何变化。

但如果1和2正常执行,操作3发生异常,操作1的数据会因为事务回滚,但操作2并不能。因此整个系统会出现一个很诡异的现象:单据系统内,没有任何日志记录,用户操作的数据也没有保留下来,但BPM那边却已经审核通过了,这在任何正常流程中,都是不可能出现的状态。

对于用户而言,他在页面会收到报错,然后可能会再次点击“审核通过”,而此时BPM那边却显示,流程已经走到下一个节点,该用户无权限操作。

问题分析

根本原因其实不难,因为MYSQL事务只能管他自己,没法控制第三方系统

解决思路

一个字:拆!

对于分布式系统,没有任何人能保证远程调用不出问题,因此在做设计时,就必须能够对这种情况做出应对

上面的操作,打包放进一个大事务就是根因,因此方案就是将大事务拆开,在拆分时,需要遵循以下几个原则:

  • 小事务内,尽量只有一个远程写操作
    
  • 该远程写操作放到方法最后,保证在其返回成功后就能立刻提交事务
    
  • 小事务可能会因为某些原因失败,因此需要机制来进行重试
    

整体思路就是这样

基于以上原则,改动如下

第一步,新建一张任务表:

CREATE TABLE `transaction_job` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`type` varchar(255) NOT NULL COMMENT '任务类型',
`data` varchar(255) NOT NULL COMMENT '任务数据',
`error_message` varchar(255) DEFAULT NULL COMMENT '错误信息',
`context` varchar(255) DEFAULT NULL COMMENT '任务上下文(主要是保存当前操作人)',
`create_time` bigint(20) NOT NULL COMMENT '创建时间',
`update_time` bigint(20) NOT NULL COMMENT '更新时间',
`retry_times` int(11) NOT NULL DEFAULT '0' COMMENT '重试次数',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='事务任务表';

作用:保存小事务的关键数据到data字段中,以保证通过该字段,就能正确执行小事务。另外也需要保存当前操作人的信息context。

第二步,通过定时任务,查出transaction_job表中未完成的数据,并执行对应的操作,这里通过简单的策略模式,将框架代码和业务代码做了分离

首先是框架代码核心逻辑

扫描任务

执行任务

这是一个策略模式接口,每个小事务就封装一个独立的实现类

其中更新待审人的任务实现如下,其实就是把那部分代码复制过来

第三步,改造业务代码,不再一次性把流程写完,而且是在第一个小事务中,顺便往transaction_job中插入一条数据,以执行第二个小事务

其中步骤2(插入任务数据的代码)的具体实现如下(transactionJobService.create)

优化

上述方案种,除第一个事务外,后续事务都是通过定时任务来执行的,因此这些事务都存在一定的延迟,用户体验不好,解决办法也非常简单,只需要利用好Spring对于事务的生命周期管理,稍微改造一下插入任务的方法(transactionJobService.create)

这是Spring提供的工具类,afterCommit()方法会在事务提交后执行,因此加上这段代码后,思路就变成了这样

如果小事务顺利执行,会立刻将该任务改为“成功”,因此从用户端是感受不到延迟的

注意

可能存在添加任务后,定时任务也立刻扫描到了这条数据,同一任务就会被主线程与定时任务线程同时执行,所以实际应用中需要考虑这个问题(比如:加锁再执行,执行前再检查数据库状态)

结语

目前只给出了解决思路的核心,但真实项目中,还添加了不少额外功能,以后会逐渐更新进来

原创 顶尖架构师栈

标签:COMMENT,事务,BPM,系统,优雅,任务,一致性,NULL,分布式
From: https://www.cnblogs.com/o-O-oO/p/18662375

相关文章

  • 【待发】【分布式】浅析分布式理论的CAP
    今天让我们来聚焦于分布式系统架构中的重要理论——CAP理论。在分布式系统中,可用性和数据一致性是两个至关重要的因素,而CAP理论就是在这两者之间提供了一种权衡的原则,帮助我们在设计分布式系统时进行决策。同时,CAP理论的出现也深刻影响着分布式系统的发展和设计。但是在当今这个时......
  • 边缘计算和分布式计算区别是什么?
    首先,需要理解什么是边缘计算和分布式计算,简要说明如下:边缘计算:是把数据处理放在网络的边缘,靠近数据源的地方,这样可以减少延迟,节省带宽。分布式计算:是把任务分配到多个节点上处理,然后把结果汇总,这样可以提高计算能力和处理大数据。边缘计算和分布式计算是两种不同的计算模......
  • Rubyer-WPF:打造优雅、精致的 WPF 用户界面
    在桌面应用开发领域,WPF(WindowsPresentationFoundation)凭借其强大的UI设计能力和丰富的功能,始终是开发者们青睐的工具之一。今天,我将为大家介绍一款专注于WPFUI设计的优秀项目——Rubyer-WPF,它将帮助开发者打造更加优雅、美观的用户界面。项目简介Rubyer-WPF 是由开发......
  • UML建模语言中不同图之间可以进行一致性检验-表示怀疑
    在UML(统一建模语言)中,**不同图之间确实可以进行一致性检验**,包括对于活动图和用例图,尤其是两者之间关键元素的一致性验证。进行这样的验证的目的,是确保建模的不同视角之间具有共同的信息基础,从而保持模型的整体完整性和一致性。以下是针对活动图与用例图的一致性验证的一些关键......
  • 分布式锁Redisson详解,Redisson如何解决不可重入,不可重试,超时释放,主从一致问题的分析解
    目录1.Redisson解决不可重入锁导致的死锁问题 2.不可重试问题Pub/Sub的优势锁释放的发布逻辑3.超时释放的问题1.锁的超时释放机制背景2.源码分析2.1锁的获取2.2看门狗机制2.3看门狗续期实现2.4手动设置锁的过期时间总结 4.主从一致性 问题背景......
  • Scala分布式语言二(基础功能搭建、面向对象基础、面向对象高级、异常、集合)
    章节3基础功能搭建46.函数作为值三packagecn.itbaizhan.chapter03//函数作为值,函数也是个对象objectFunctionToTypeValue{defmain(args:Array[String]):Unit={  //Studentstu=newStudent()  /*val......
  • FastAPI 依赖注入、异步任务与分布式调度
    FastAPI依赖注入、异步任务与分布式调度目录......
  • 【分布式技术】Springboot集成zookeeper
    文章目录作为服务发现步骤1:添加依赖步骤2:配置Zookeeperapplication.propertiesapplication.yml步骤3:启用服务发现步骤4:运行你的应用注意事项作为客户端使用场景1.**配置管理**2.**命名服务(NameService)**3.**分布式锁**4.**集群管理**5.**选举主节点(LeaderElecti......
  • Rubyer-WPF:打造优雅、精致的 WPF 用户界面
    这篇文章可以通过一些结构性的调整和文字优化,使得内容更具吸引力和流畅感。以下是改进后的版本:Rubyer-WPF:打造优雅、精致的WPF用户界面在桌面应用开发领域,WPF(WindowsPresentationFoundation)凭借其强大的UI设计能力和丰富的功能,始终是开发者们青睐的工具之一。今天,我将为......
  • 写一个支持折叠、有缩进、代码高亮、离线的,方便部署的、易用的、优雅的json格式化查看
    缘由网上的在线json格式化有很多,但我是个有追求的人。在线的很难同时支持折叠、有缩进线、代码高亮、离线的,方便部署的、易用的、不请求后端(为了安全)的json格式化工具。去Github上找项目,华而不实的东西占半个屏幕,格式化json要点好几下,一个json格式化工具npm安装之后几百个文件。......