资讯专栏INFORMATION COLUMN

Spring事务&分布式事务&单服务处理多数据源事务

社区管理员 / 834人阅读

本文以一个实际业务问题来谈谈事务该如何处理。对接外部系统是是不可避免的,从广泛意义上来说,外部系统范围很大,中间件(数据库)也属于外部系统。当我们讨论事务时,通常我们将那些没有支持事务的系统称为外部系统,业务系统基本上都是外部系统。

问题

有这样一套系统,以gitlab为底层系统, 在gitlab project的基础上封装了代码仓,系统对其中一些与gitlab关联的数据进行了落表。创建代码仓的逻辑过程比较复杂,首先通过gitlab创建代码仓(其中返回的代码仓id需要落库),系统表code_repo插入记录,创建gitlabhook,系统表member插入记录(维护系统用户和对应代码仓的关系),创建多个gitlabbranch(系统业务,初始化代码仓可以初始化多个分支),系统表label插入记录。

分析

以上大概说明整个业务流程, gitlab接入的方式采用HTTP,不采用直接对接gitlab数据库的原因是,其创建项目和分支业务逻辑复杂,梳理代价很大。对接任何系统其实本质上可以概括为两种:

对接方式优势缺点
上游系统提供的接口不需要关注上游系统的自身义务逻辑,维护只需要关注接口版本灵活性较差
上游系统底层存储(数据库,文件等)需要梳理和维护上游系统业务逻辑,维护是代码层面的灵活性、可控性很好

,数据库采用mysql。 在不考虑异常的情况,整个业务流程还是比较清晰的,但是分布式的核心就是处理各种异常情况,这也是分布式复杂的地方。因为分布式的网络环境是很复杂的。我们很保证底层系统的可用性。在这里,当gitlab其中的接口出现异常,系统仍落库显然是不合理的,同样的当数据库发生异常,gitlab数据存在也是不合理的,分布式事务的核心要解决数据一致性。

解决还需要与当前的项目架构不能冲突。目前各服务还没有拆分,运行。数据库也没有拆分。其架构仍是单体架构模式,设计时考虑了后期的微服务拆分。目前主要问题是解决GitlabDB之间的数据一致性,其复杂度没有微服务多DB的高。

分布式事务(浅谈)

事务的概念来自数据库事务,在数据库事务定义中,事务是一个执行的逻辑单元,它需要提供一个一致、可靠的数据操作,它主要包括下面两个目标:

  1. 当出现任何错误,包括系统宕机、部分失败,都能保证左右的数据修改都能够恢复到未修改的状态;

  2. 不通的事务并发处理相同的数据时,提供适当的隔离机制。 我们常说的ACID,其实是某些数据库特有的事务实现方式,也就是实现了原子性、一致性、隔离性和持久性。 dan 分布式事务,一直是实现分布式系统过程中最大的挑战,在单个数据源的系统中,只要该数据源支持事务,例如大部分关系型数据库,一些MQ服务(redis,mysql,activeMQ等),我们实现事务相对容易。那么我们如何在分布式系统中实现事务呢?这就要从分布式系统的原则说起,目前主要有BASE原理 ACP原理。其中ACP是:

  3. A:可用性(Availability)

  4. B:一致性(Consistency)

  5. C:分区容错性(Tolerance of network Partition) ruan zhuang t爱 A和P没什么好说的,就是分布式系统的基本特性,C(一致性)指在分布式系统中,多个节点之间的数据的一致性,包括一个节点修改的数据,通过另一个节点访问的时候也能够看到;以及当一个操作需要修改多个数据源的数据,多个修改都能够同时完成或者同时不完成。

这里的一致性,我们可以看作是数据库事务的ACID特性中,原子性、一致性甚至是隔离性的统一。如果以ACID标准实现分布式系统,在现实中是不可能的。其中原子性就没法实现,如果一个业务请求,要修改多个数据库中的数据,那么这多个数据库操作,就无法实现原子性,势必会有一个先后,这一点点时间就违反了原子性。

所以,我们往往无法在分布式系统中实现完全的一致性,所以就有了BASE理论,BASE是BasicallAvailable(基本可用),SOftstate(软状态)和Eventually consistent(最终一致性)三个短语的缩写。BASE理论是对CAP中一致性和可用性权衡的结果,要求实现最终一致性即可。

其中,SoftState(软状态)是指,在一个业务操作过程中,允许出现一个中间状态,也就是软状态,而不是要求原子性那样,要么完成要么不完成。例如在下单的时候,出现一个正在处理状态。由于有这个软状态,那我的一致性就不是要求抢一致性,而是最终一致性,也就是说,只要最终这个请求能够处理完,所有数据状态都是处理完的状态;如果期间出错了,所有的数据也都一致,该失败的失败,该退钱的退钱,该重置的重置。 确定分布式系统的实现原则是最终一致性以后,同时也明确了我们实现分布式事务的原则,也是最终一致性。其实,不管数据库事务的ACID特性,还是分布式事务的最终一致性,都是根据事务的定义和它的两个目标,所采用的不通的实现方式。

那我们该如何实现这个最终一致性呢?

image.png

单服务的分布式事务

首先,任何一个分布式系统,总是由一个个的系统组成,也就是一个个的服务,这些服务也可以部署多个实例。同时,我们整个系统也需要一定的方式相互通信。我们采用接口的方式,也可以通过MQ之类的消息中间件通信。但是无论怎样,分布式系统会涉及多个数据源。

对于这种每个服务访问多个数据源的情况,其实就是一个最简单的分布式事务的场景。如果大家在网上搜“Spring分布式事务实现”,搜索到结果也就是在说这个场景下的分布式事务实现过程。要实现这个事务,首先需要对Spring的事务机制有一定的了解。对于这种情况,最简单的就是使用Springde JTA事务管理,但是我们知道。JTAs事务管理是通过两阶段提交实现的,在很多情况下,他的效率是很低的。因为它在多个数据源秀修改数据的时候,这些数据一直处在被锁的状态,直到多个数据源的事务都提交完成,才会释放。

如果不用JTA,Spring也给我们提供了几种方式,来近似的实现分布式事务,例如:

  1. 事务同步,也就是提交一个事务的时候,通过Listener等方式通知另一个事务也提交。但是这种情况下,如果第二个事务提交出错了,第一个事务就无法回滚了,因为它已经提交完成了

  2. 链式事务,也就是将多个事务,包装在一个链式事务管理器中,当提交事务的时候,一次提交里面的事务,对于这种情况,也存在上面所说的问题

所以,使用spring在单服务多数据源的情况下,实现分布式事务,实际上没办法完全实现事务的,因为出错的时候不能够保证。那么这时候,就需要通过其他机制来补充。比如重试,自己处理错误和异常。
大家可以试想一下,分布式系统越复杂,它出错的情况就越多,我们需要考虑的补救措施就越多。这种修修补补的实现分布式事务的最终一致性的做法,始终不是一个好做法。但是,使用Spring解决单服务的分布式系统,始终是分布式事务实现的基础。我们可以用其他的模式来方便我们解决分布式事务,但是在每个服务中,我们还是要经常使用事务同步、链式事务等来实现事务。我们用Spring来保证绝大数情况下的事务问题,而对于特殊的错误情况,就采用其他的模式来解决。

分布式事务实现的模式

刚才说了我们使用其他模式来处理分布式事务问题,主要有下面五种模式,参考 分布式事务参考 

  1. XA方案

  2. TCC方案

  3. 本地消息表

  4. 可靠消息最终一直方案

  5. 最大努力通知方案

解决

由于目前是单DB,可以尽最大限度利用单DB事务特性,Spring事务管理中介绍了有两种事务管理方式(programmatically and declarative )。 虽然官方文档建议使用申明式事务管理方式,但是我们在回滚数据库事务需要执行其他操作时,如API的反操作,手动方式才能够实现。

CoderepoService中提供的创建代码仓接口createCodeRepo,主要包含①②③④操作,其中只有一个DB操作④,使用数据库事务无法满足情况。 例如当①②执行成功,③执行失败,这是通过异常事务回滚无法回滚Gitlab中的数据。所以必须手动回滚,处理逻辑如下。我们Spring数据库事务,保证DB操作, 当③④失败时手动捕获异常(回滚gitlab数据),并抛出系统业务异常(使事务生效)。

image.png

这里涉及的Gitlab操作对应一个回滚操作deleteGitlabProject(),DB通过事务回滚。

总结

本文讨论问题类似单服务多DB场景,不同的是gitlab数据与通是保证通过HTTP调用的,并没有实现事务。 如何保证DB与第三方系统数据保持一致性的问题,尽量较小的代码改动。在微服务多数据源的情况下不能够满足需求,需要根据业务选型。


文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/127925.html

相关文章

  • 超实用百道Java面试题

    摘要:是的简称,运行环境,为的运行提供了所需的环境。分割字符串,返回分割后的字符串数组。当计算的值相同时,我们称之为冲突,的做法是用链表和红黑树存储相同的值的。迭代器取代了集合框架中的,迭代器允许调用者在迭代过程中移除元素。 Java基础1.JDK和JRE有什么区别? JDK 是java development kit的简称,java开发工具包,提供java的开发环境和运行环境。JRE 是j...

    MkkHou 评论0 收藏0
  • 近期Java高级工程师面试总结

    摘要:面试总结最近两周面试了几家公司高级工程师的职位,主要有宜信网信金融阿里高德口袋购物。目前有部分公司已经面试通过,两家在等消息。今天趁热把常见面试内容总结一下。可以用来完成统一命名服务状态同步服务集群管理分布式应用配置项等管理工作。 面试总结 最近两周面试了几家公司Java高级工程师的职位,主要有宜信、网信金融、阿里高德、口袋购物。目前有部分公司已经面试通过,两家在等消息。今天趁热把常见...

    raoyi 评论0 收藏0
  • Spring Cloud 布式事务管理

    摘要:中大致分为两部分事务管理器和本地资源管理器。具体实现分布式事务框架的核心功能是对本地事务的协调控制,框架本身并不创建事务,只是对本地事务做协调控制。 Spring Cloud 分布式事务管理 在微服务如火如荼的情况下,越来越多的项目开始尝试改造成微服务架构,微服务即带来了项目开发的方便性,又提高了运维难度以及网络不可靠的概率. @[toc]在说微服务的优缺点时,有对比才会更加明显,首先...

    aboutU 评论0 收藏0
  • Spring Boot 参考指南(使用JTA布式事务

    摘要:使用事务管理器是支持的一个流行的开源事务管理器实现,你可以使用启动器向项目添加适当的依赖项,与和一样,将自动配置并对进行后处理,以确保启动和关闭顺序是正确的。 37. 用JTA分布式事务 通过使用Atomikos或Bitronix嵌入式事务管理器,Spring Boot支持跨多个XA资源的分布式JTA事务,在部署到合适的Java EE应用服务器时也支持JTA事务。 当检测到JTA环境时...

    silenceboy 评论0 收藏0
  • 事务Transaction

    摘要:只有在事务确定正确提交之后,才会显示该事务对数据的改变。不允许不一致现象的出现。 @[TOC] 为什么写这系列的文章 在日常的工作和开发中,接触最多的便是与数据库打交道,无论你使用什么框架进行开发都绕不开事务的管理. 在Java开发中你可能会接触很多ORM框架,无论是Hibernate、MyBatis、还是Spring Jdbc 都会遇到事务的相关操作,再到中大型项目,你还会遇到单一数...

    DirtyMind 评论0 收藏0

发表评论

0条评论

社区管理员

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<