您当前的位置:首页 > 电脑百科 > 程序开发 > 架构

微服务架构下的分布式事务基础入门

时间:2019-08-27 09:40:14  来源:  作者:

好文推荐:微服务架构下的分布式事务基础入门

众所周知,数据库能实现本地事务,也就是在同一个数据库中,你可以允许一组操作要么全都正确执行,要么全都不执行。这里特别强调了本地事务,也就是目前的数据库只能支持同一个数据库中的事务。但现在的系统往往采用微服务架构,业务系统拥有独立的数据库,因此就出现了跨多个数据库的事务需求,这种事务即为“分布式事务”。那么在目前数据库不支持跨库事务的情况下,我们应该如何实现分布式事务呢?本文首先会为大家梳理分布式事务的基本概念和理论基础,然后介绍几种目前常用的分布式事务解决方案。废话不多说,那就开始吧~

1. 什么是事务?

事务由一组操作构成,我们希望这组操作能够全部正确执行,如果这一组操作中的任意一个步骤发生错误,那么就需要回滚之前已经完成的操作。也就是同一个事务中的所有操作,要么全都正确执行,要么全都不要执行。

2. 事务的四大特性 ACID

说到事务,就不得不提一下事务著名的四大特性。

  • 原子性
  • 原子性要求,事务是一个不可分割的执行单元,事务中的所有操作要么全都执行,要么全都不执行。
  • 一致性
  • 一致性要求,事务在开始前和结束后,数据库的完整性约束没有被破坏。
  • 隔离性
  • 事务的执行是相互独立的,它们不会相互干扰,一个事务不会看到另一个正在运行过程中的事务的数据。
  • 持久性
  • 持久性要求,一个事务完成之后,事务的执行结果必须是持久化保存的。即使数据库发生崩溃,在数据库恢复后事务提交的结果仍然不会丢失。
注意:事务只能保证数据库的高可靠性,即数据库本身发生问题后,事务提交后的数据仍然能恢复;而如果不是数据库本身的故障,如硬盘损坏了,那么事务提交的数据可能就丢失了。这属于『高可用性』的范畴。因此,事务只能保证数据库的『高可靠性』,而『高可用性』需要整个系统共同配合实现。

3. 事务的隔离级别

这里扩展一下,对事务的隔离性做一个详细的解释。

在事务的四大特性ACID中,要求的隔离性是一种严格意义上的隔离,也就是多个事务是串行执行的,彼此之间不会受到任何干扰。这确实能够完全保证数据的安全性,但在实际业务系统中,这种方式性能不高。因此,数据库定义了四种隔离级别,隔离级别和数据库的性能是呈反比的,隔离级别越低,数据库性能越高,而隔离级别越高,数据库性能越差。

3.1 事务并发执行会出现的问题

我们先来看一下在不同的隔离级别下,数据库可能会出现的问题:

  1. 更新丢失
  2. 当有两个并发执行的事务,更新同一行数据,那么有可能一个事务会把另一个事务的更新覆盖掉。
  3. 当数据库没有加任何锁操作的情况下会发生。
  4. 脏读
  5. 一个事务读到另一个尚未提交的事务中的数据。
  6. 该数据可能会被回滚从而失效。
  7. 如果第一个事务拿着失效的数据去处理那就发生错误了。
  8. 不可重复读
  9. 不可重复度的含义:一个事务对同一行数据读了两次,却得到了不同的结果。它具体分为如下两种情况:
  • 虚读:在事务1两次读取同一记录的过程中,事务2对该记录进行了修改,从而事务1第二次读到了不一样的记录。
  • 幻读:事务1在两次查询的过程中,事务2对该表进行了插入、删除操作,从而事务1第二次查询的结果发生了变化。
不可重复读 与 脏读 的区别? 脏读读到的是尚未提交的数据,而不可重复读读到的是已经提交的数据,只不过在两次读的过程中数据被另一个事务改过了。

3.2 数据库的四种隔离级别

数据库一共有如下四种隔离级别:

  1. Read uncommitted 读未提交
  2. 在该级别下,一个事务对一行数据修改的过程中,不允许另一个事务对该行数据进行修改,但允许另一个事务对该行数据读。
  3. 因此本级别下,不会出现更新丢失,但会出现脏读、不可重复读。
  4. Read committed 读提交
  5. 在该级别下,未提交的写事务不允许其他事务访问该行,因此不会出现脏读;但是读取数据的事务允许其他事务的访问该行数据,因此会出现不可重复读的情况。
  6. Repeatable read 重复读
  7. 在该级别下,读事务禁止写事务,但允许读事务,因此不会出现同一事务两次读到不同的数据的情况(不可重复读),且写事务禁止其他一切事务。
  8. Serializable 序列化
  9. 该级别要求所有事务都必须串行执行,因此能避免一切因并发引起的问题,但效率很低。

隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed。它能够避免脏读取,而且具有较好的并发性能。尽管它会导致不可重复读、幻读和第二类丢失更新这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。

4. 什么是分布式事务?

到此为止,所介绍的事务都是基于单数据库的本地事务,目前的数据库仅支持单库事务,并不支持跨库事务。而随着微服务架构的普及,一个大型业务系统往往由若干个子系统构成,这些子系统又拥有各自独立的数据库。往往一个业务流程需要由多个子系统共同完成,而且这些操作可能需要在一个事务中完成。在微服务系统中,这些业务场景是普遍存在的。此时,我们就需要在数据库之上通过某种手段,实现支持跨数据库的事务支持,这也就是大家常说的“分布式事务”。

这里举一个分布式事务的典型例子——用户下单过程。

当我们的系统采用了微服务架构后,一个电商系统往往被拆分成如下几个子系统:商品系统、订单系统、支付系统、积分系统等。整个下单的过程如下:

  1. 用户通过商品系统浏览商品,他看中了某一项商品,便点击下单
  2. 此时订单系统会生成一条订单
  3. 订单创建成功后,支付系统提供支付功能
  4. 当支付完成后,由积分系统为该用户增加积分

上述步骤2、3、4需要在一个事务中完成。对于传统单体应用而言,实现事务非常简单,只需将这三个步骤放在一个方法A中,再用Spring的@Transactional注解标识该方法即可。Spring通过数据库的事务支持,保证这些步骤要么全都执行完成,要么全都不执行。但在这个微服务架构中,这三个步骤涉及三个系统,涉及三个数据库,此时我们必须在数据库和应用系统之间,通过某项黑科技,实现分布式事务的支持。

5. CAP理论

CAP理论说的是:在一个分布式系统中,最多只能满足C、A、P中的两个需求。

CAP的含义:

  • C:Consistency 一致性
  • 同一数据的多个副本是否实时相同。
  • A:Availability 可用性
  • 可用性:一定时间内 & 系统返回一个明确的结果 则称为该系统可用。
  • P:Partition tolerance 分区容错性
  • 将同一服务分布在多个系统中,从而保证某一个系统宕机,仍然有其他系统提供相同的服务。

CAP理论告诉我们,在分布式系统中,C、A、P三个条件中我们最多只能选择两个。那么问题来了,究竟选择哪两个条件较为合适呢?

对于一个业务系统来说,可用性和分区容错性是必须要满足的两个条件,并且这两者是相辅相成的。业务系统之所以使用分布式系统,主要原因有两个:

  • 提升整体性能
  • 当业务量猛增,单个服务器已经无法满足我们的业务需求的时候,就需要使用分布式系统,使用多个节点提供相同的功能,从而整体上提升系统的性能,这就是使用分布式系统的第一个原因。
  • 实现分区容错性
  • 单一节点 或 多个节点处于相同的网络环境下,那么会存在一定的风险,万一该机房断电、该地区发生自然灾害,那么业务系统就全面瘫痪了。为了防止这一问题,采用分布式系统,将多个子系统分布在不同的地域、不同的机房中,从而保证系统高可用性。

这说明分区容错性是分布式系统的根本,如果分区容错性不能满足,那使用分布式系统将失去意义。

此外,可用性对业务系统也尤为重要。在大谈用户体验的今天,如果业务系统时常出现“系统异常”、响应时间过长等情况,这使得用户对系统的好感度大打折扣,在互联网行业竞争激烈的今天,相同领域的竞争者不甚枚举,系统的间歇性不可用会立马导致用户流向竞争对手。因此,我们只能通过牺牲一致性来换取系统的可用性分区容错性。这也就是下面要介绍的BASE理论。

6. BASE理论

CAP理论告诉我们一个悲惨但不得不接受的事实——我们只能在C、A、P中选择两个条件。而对于业务系统而言,我们往往选择牺牲一致性来换取系统的可用性和分区容错性。不过这里要指出的是,所谓的“牺牲一致性”并不是完全放弃数据一致性,而是牺牲强一致性换取弱一致性。下面来介绍下BASE理论。

  • BA:Basic Available 基本可用
  • “一定时间”可以适当延长
  • 当举行大促时,响应时间可以适当延长
  • 给部分用户返回一个降级页面
  • 给部分用户直接返回一个降级页面,从而缓解服务器压力。但要注意,返回降级页面仍然是返回明确结果。
  • 整个系统在某些不可抗力的情况下,仍然能够保证“可用性”,即一定时间内仍然能够返回一个明确的结果。只不过“基本可用”和“高可用”的区别是:
  • S:Soft State:柔性状态
  • 同一数据的不同副本的状态,可以不需要实时一致。
  • E:Eventual Consisstency:最终一致性
  • 同一数据的不同副本的状态,可以不需要实时一致,但一定要保证经过一定时间后仍然是一致的。

7. 酸碱平衡

ACID能够保证事务的强一致性,即数据是实时一致的。这在本地事务中是没有问题的,在分布式事务中,强一致性会极大影响分布式系统的性能,因此分布式系统中遵循BASE理论即可。但分布式系统的不同业务场景对一致性的要求也不同。如交易场景下,就要求强一致性,此时就需要遵循ACID理论,而在注册成功后发送短信验证码等场景下,并不需要实时一致,因此遵循BASE理论即可。因此要根据具体业务场景,在ACID和BASE之间寻求平衡。

8. 分布式事务协议

下面介绍几种实现分布式事务的协议。

8.1 两阶段提交协议 2PC

分布式系统的一个难点是如何保证架构下多个节点在进行事务性操作的时候保持一致性。为实现这个目的,二阶段提交算法的成立基于以下假设:

  • 该分布式系统中,存在一个节点作为协调者(Coordinator),其他节点作为参与者(Cohorts)。且节点之间可以进行网络通信。
  • 所有节点都采用预写式日志,且日志被写入后即被保持在可靠的存储设备上,即使节点损坏不会导致日志数据的消失。
  • 所有节点不会永久性损坏,即使损坏后仍然可以恢复。

1. 第一阶段(投票阶段):

  1. 协调者节点向所有参与者节点询问是否可以执行提交操作(vote),并开始等待各参与者节点的响应。
  2. 参与者节点执行询问发起为止的所有事务操作,并将Undo信息和Redo信息写入日志。(注意:若成功这里其实每个参与者已经执行了事务操作)
  3. 各参与者节点响应协调者节点发起的询问。如果参与者节点的事务操作实际执行成功,则它返回一个"同意"消息;如果参与者节点的事务操作实际执行失败,则它返回一个"中止"消息。

2. 第二阶段(提交执行阶段):

当协调者节点从所有参与者节点获得的相应消息都为"同意"时:

  1. 协调者节点向所有参与者节点发出"正式提交(commit)"的请求。
  2. 参与者节点正式完成操作,并释放在整个事务期间内占用的资源。
  3. 参与者节点向协调者节点发送"完成"消息。
  4. 协调者节点受到所有参与者节点反馈的"完成"消息后,完成事务。

如果任一参与者节点在第一阶段返回的响应消息为"中止",或者 协调者节点在第一阶段的询问超时之前无法获取所有参与者节点的响应消息时:

  1. 协调者节点向所有参与者节点发出"回滚操作(rollback)"的请求。
  2. 参与者节点利用之前写入的Undo信息执行回滚,并释放在整个事务期间内占用的资源。
  3. 参与者节点向协调者节点发送"回滚完成"消息。
  4. 协调者节点受到所有参与者节点反馈的"回滚完成"消息后,取消事务。

不管最后结果如何,第二阶段都会结束当前事务。

二阶段提交看起来确实能够提供原子性的操作,但是不幸的事,二阶段提交还是有几个缺点的:

  1. 执行过程中,所有参与节点都是事务阻塞型的。当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态。
  2. 参与者发生故障。协调者需要给每个参与者额外指定超时机制,超时后整个事务失败。(没有多少容错机制)
  3. 协调者发生故障。参与者会一直阻塞下去。需要额外的备机进行容错。(这个可以依赖后面要讲的Paxos协议实现HA)
  4. 二阶段无法解决的问题:协调者再发出commit消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了。那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,没人知道事务是否被已经提交。

为此,Dale Skeen和Michael Stonebraker在“A Formal Model of Crash Recovery in a Distributed System”中提出了三阶段提交协议(3PC)。

8.2 三阶段提交协议 3PC

与两阶段提交不同的是,三阶段提交有两个改动点。

  • 引入超时机制。同时在协调者和参与者中都引入超时机制。
  • 在第一阶段和第二阶段中插入一个准备阶段。保证了在最后提交阶段之前各参与节点的状态是一致的。

也就是说,除了引入超时机制之外,3PC把2PC的准备阶段再次一分为二,这样三阶段提交就有CanCommit、PreCommit、DoCommit三个阶段。

1. CanCommit阶段

3PC的CanCommit阶段其实和2PC的准备阶段很像。协调者向参与者发送commit请求,参与者如果可以提交就返回Yes响应,否则返回No响应。

  1. 事务询问
  2. 协调者向参与者发送CanCommit请求。询问是否可以执行事务提交操作。然后开始等待参与者的响应。
  3. 响应反馈
  4. 参与者接到CanCommit请求之后,正常情况下,如果其自身认为可以顺利执行事务,则返回Yes响应,并进入预备状态。否则反馈No

2. PreCommit阶段

协调者根据参与者的反应情况来决定是否可以记性事务的PreCommit操作。根据响应情况,有以下两种可能。

假如协调者从所有的参与者获得的反馈都是Yes响应,那么就会执行事务的预执行。

  1. 发送预提交请求
  2. 协调者向参与者发送PreCommit请求,并进入Prepared阶段。
  3. 事务预提交
  4. 参与者接收到PreCommit请求后,会执行事务操作,并将undo和redo信息记录到事务日志中。
  5. 响应反馈
  6. 如果参与者成功的执行了事务操作,则返回ACK响应,同时开始等待最终指令。

假如有任何一个参与者向协调者发送了No响应,或者等待超时之后,协调者都没有接到参与者的响应,那么就执行事务的中断。

  1. 发送中断请求
  2. 协调者向所有参与者发送abort请求。
  3. 中断事务
  4. 参与者收到来自协调者的abort请求之后(或超时之后,仍未收到协调者的请求),执行事务的中断。

3. doCommit阶段

该阶段进行真正的事务提交,也可以分为以下两种情况。

该阶段进行真正的事务提交,也可以分为以下两种情况。

3.1 执行提交

  1. 发送提交请求
  2. 协调接收到参与者发送的ACK响应,那么他将从预提交状态进入到提交状态。并向所有参与者发送doCommit请求。
  3. 事务提交
  4. 参与者接收到doCommit请求之后,执行正式的事务提交。并在完成事务提交之后释放所有事务资源。
  5. 响应反馈
  6. 事务提交完之后,向协调者发送Ack响应。
  7. 完成事务
  8. 协调者接收到所有参与者的ack响应之后,完成事务。

3.2 中断事务

协调者没有接收到参与者发送的ACK响应(可能是接受者发送的不是ACK响应,也可能响应超时),那么就会执行中断事务。

  1. 发送中断请求
  2. 协调者向所有参与者发送abort请求
  3. 事务回滚
  4. 参与者接收到abort请求之后,利用其在阶段二记录的undo信息来执行事务的回滚操作,并在完成回滚之后释放所有的事务资源。
  5. 反馈结果
  6. 参与者完成事务回滚之后,向协调者发送ACK消息
  7. 中断事务
  8. 协调者接收到参与者反馈的ACK消息之后,执行事务的中断。

最后

另外,如果觉得本文对您有帮助的话,记得关注Wooola、转发哦,我会为大家持续提供原创干货。

原文链接:https://mp.weixin.qq.com/s/VbFOscil4s4XEbhznisvhQ



Tags:微服务架构   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
前言要理解微服务,首先要先理解不是微服务的那些。通常跟微服务相对的是单体应用,即将所有功能都打包成在一个独立单元的应用程序。从单体应用到微服务并不是一蹴而就的,这是一...【详细内容】
2021-07-09  Tags: 微服务架构  点击:(112)  评论:(0)  加入收藏
一、Zuul简介Zuul相当于是第三方调用和服务提供方之间的防护门,其中最大的亮点就是可动态发布过滤器二、Zuul可以为我们提供什么1、权限控制2、预警和监控3、红绿部署、(粘...【详细内容】
2021-04-21  Tags: 微服务架构  点击:(230)  评论:(0)  加入收藏
前不久作为架构师完成了某知名快消企业的一个业务中台建设。系统上线后,经历了双十一活动的流量高峰,整体运行稳定。最近有空,便将此次架构的思路,心得稍作整理在这篇博客中分享...【详细内容】
2021-02-07  Tags: 微服务架构  点击:(182)  评论:(0)  加入收藏
文章简介:作者结合自身微服务架构研发经验进行回顾、总结,本文将介绍微服务架构中,在技术选型时需要注意哪些选型原则,会遇到哪些开源框架,又该如何选择, 进行了全面的归纳、对比,希望能够为大家提供一些思路、方向,少走一些...【详细内容】
2021-02-05  Tags: 微服务架构  点击:(160)  评论:(0)  加入收藏
思维导图 文章已收录Github精选,欢迎Star:https://github.com/yehongzhi/learningSummary一、前言伴随着Eurka2.0版本已停止维护,开始要考虑使用微服务新一代的开源的注册中心...【详细内容】
2020-11-13  Tags: 微服务架构  点击:(159)  评论:(0)  加入收藏
消息总线的定义前面在1.4.2节中强调过,在微服务架构中,经常会使用REST 服务或基于消息的通信机制。在3.6节中也详细介绍了消息通信的实现方式。消息总线就是一种基于消息的通...【详细内容】
2020-09-29  Tags: 微服务架构  点击:(141)  评论:(0)  加入收藏
微服务的高级主题一自动扩展Spring Cloud 提供了大规模部署微服务所必需的支持。为了获得像云服务环境一样的能力, 微服务实例也应该能够根据流量的规模来自动扩展,也称自动缩...【详细内容】
2020-09-23  Tags: 微服务架构  点击:(96)  评论:(0)  加入收藏
Spring Cloud 微服务总体架构图Spring cloud作为当下主流的微服务框架,让我们实现微服务架构简单快捷,Spring cloud中各个组件在微服务架构中扮演的角色如图所示。spring-cl...【详细内容】
2020-09-20  Tags: 微服务架构  点击:(133)  评论:(0)  加入收藏
常见微服务的消费者本节就常见的微服务的消费者进行介绍。在Java领域比较常用的消费者框架主要有HttpClient、Ribbon、Feign 等。 Apache HttpClientApache HttpClient是Apa...【详细内容】
2020-09-11  Tags: 微服务架构  点击:(129)  评论:(0)  加入收藏
什么是微服务模式随着网络基础设施的高速发展,以及越来越多的个体接入互联网,在考虑构建支持海量请求以及多变业务的软件平台时,微服务架构成为多数人的首选。微服务架构的出现...【详细内容】
2020-09-09  Tags: 微服务架构  点击:(95)  评论:(0)  加入收藏
▌简易百科推荐
为了构建高并发、高可用的系统架构,压测、容量预估必不可少,在发现系统瓶颈后,需要有针对性地扩容、优化。结合楼主的经验和知识,本文做一个简单的总结,欢迎探讨。1、QPS保障目标...【详细内容】
2021-12-27  大数据架构师    Tags:架构   点击:(5)  评论:(0)  加入收藏
前言 单片机开发中,我们往往首先接触裸机系统,然后到RTOS,那么它们的软件架构是什么?这是我们开发人员必须认真考虑的问题。在实际项目中,首先选择软件架构是非常重要的,接下来我...【详细内容】
2021-12-23  正点原子原子哥    Tags:架构   点击:(7)  评论:(0)  加入收藏
现有数据架构难以支撑现代化应用的实现。 随着云计算产业的快速崛起,带动着各行各业开始自己的基于云的业务创新和信息架构现代化,云计算的可靠性、灵活性、按需计费的高性价...【详细内容】
2021-12-22    CSDN  Tags:数据架构   点击:(10)  评论:(0)  加入收藏
▶ 企业级项目结构封装释义 如果你刚毕业,作为Java新手程序员进入一家企业,拿到代码之后,你有什么感觉呢?如果你没有听过多模块、分布式这类的概念,那么多半会傻眼。为什么一个项...【详细内容】
2021-12-20  蜗牛学苑    Tags:微服务   点击:(9)  评论:(0)  加入收藏
我是一名程序员关注我们吧,我们会多多分享技术和资源。进来的朋友,可以多了解下青锋的产品,已开源多个产品的架构版本。Thymeleaf版(开源)1、采用技术: springboot、layui、Thymel...【详细内容】
2021-12-14  青锋爱编程    Tags:后台架构   点击:(21)  评论:(0)  加入收藏
在了解连接池之前,我们需要对长、短链接建立初步认识。我们都知道,网络通信大部分都是基于TCP/IP协议,数据传输之前,双方通过“三次握手”建立连接,当数据传输完成之后,又通过“四次挥手”释放连接,以下是“三次握手”与“四...【详细内容】
2021-12-14  架构即人生    Tags:连接池   点击:(17)  评论:(0)  加入收藏
随着移动互联网技术的快速发展,在新业务、新领域、新场景的驱动下,基于传统大型机的服务部署方式,不仅难以适应快速增长的业务需求,而且持续耗费高昂的成本,从而使得各大生产厂商...【详细内容】
2021-12-08  架构驿站    Tags:分布式系统   点击:(23)  评论:(0)  加入收藏
本系列为 Netty 学习笔记,本篇介绍总结Java NIO 网络编程。Netty 作为一个异步的、事件驱动的网络应用程序框架,也是基于NIO的客户、服务器端的编程框架。其对 Java NIO 底层...【详细内容】
2021-12-07  大数据架构师    Tags:Netty   点击:(17)  评论:(0)  加入收藏
前面谈过很多关于数字化转型,云原生,微服务方面的文章。虽然自己一直做大集团的SOA集成平台咨询规划和建设项目,但是当前传统企业数字化转型,国产化和自主可控,云原生,微服务是不...【详细内容】
2021-12-06  人月聊IT    Tags:架构   点击:(23)  评论:(0)  加入收藏
微服务看似是完美的解决方案。从理论上来说,微服务提高了开发速度,而且还可以单独扩展应用的某个部分。但实际上,微服务带有一定的隐形成本。我认为,没有亲自动手构建微服务的经历,就无法真正了解其复杂性。...【详细内容】
2021-11-26  GreekDataGuy  CSDN  Tags:单体应用   点击:(35)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条