【分布式技术专题】「架构实践于案例分析」盘点互联网应用服务中常用分布式事务(刚性事务和柔性事务)的原理和方案

简介: 【分布式技术专题】「架构实践于案例分析」盘点互联网应用服务中常用分布式事务(刚性事务和柔性事务)的原理和方案

前提介绍

通过之前的两篇文章《【分布式技术专题】「架构实践于案例分析」总结和盘点目前常用分布式事务特别及问题分析(上)》和《【分布式技术专题】「架构实践于案例分析」总结和盘点目前常用分布式事务特别及问题分析(中)》,您已经对微服务架构中常用的分布式事务解决方案有了初步的了解。接下来,我们将对这些解决方案进行综合分析和总结。

在这两篇文章中,我们深入探讨了分布式事务的重要性和挑战,并介绍了几种常用的分布式事务解决方案,如两阶段提交、补偿事务和消息队列等。这些解决方案在不同的场景下具有各自的优势和适用性。

知识系统回顾

事务

事务是一组操作,它们被组织在一起形成一个可靠、独立的工作单元。这个工作单元能够保证一系列操作的完整性和一致性,即使在系统故障或其他异常情况下也能保持数据的完整性和一致性。

ACID

事务处理是数据库管理系统中的基本概念,用于维护数据库的完整性和一致性,以及在多个用户之间实现并发控制和数据共享。事务具有原子性、一致性、隔离性和持久性的特性,确保数据库操作的正确性和可靠性。

事务的难点

  • 高度并发:当多个事务同时对数据库进行操作时,如何确保每个事务都能够正确、独立地完成,并且不会相互干扰,是事务处理的一大挑战。高度并发可能导致资源争用、死锁和数据不一致等问题,需要采取有效的并发控制策略来处理。
  • 资源分布:在分布式数据库系统中,事务可能涉及多个节点和资源,如数据存储、网络通信等。资源分布的复杂性增加了事务处理的难度,需要确保事务在分布式环境中的一致性、可靠性和原子性。
  • 大时间跨度:一些事务可能需要较长时间来完成,如批处理、大数据处理等。在这种情况下,事务的执行可能会受到系统故障、网络中断或其他异常因素的影响。为了确保大时间跨度的事务能够正确完成,需要采取持久性机制、恢复机制和事务回滚等技术来保证数据的一致性和完整性。

刚性事务和柔性事务

分布式事务总体可以分为两大种类型:刚性事务和柔性事务。

刚性事务

事务是由资源管理器(如数据库管理系统,DBMS)在本地进行管理的。它仅限于单个数据库的本地操作,并且仅限于单个进程内。因此,本地事务并不涉及多个数据来源。

这种事务处理方式具有局限性,但在处理单个数据库和进程中的数据操作时,可以提供良好的完整性和一致性保证。

优点

局限

本地事务的问题主要包括不具备分布事务处理能力和隔离的最小单位由资源管理器决定。

  • 本地事务只能处理单个数据库或单个进程内的事务,而无法处理跨多个数据库或分布式环境的事务。

在分布式系统中,数据可能分布在多个节点上,需要协调和同步各个节点上的事务操作以保证数据一致性和完整性。本地事务无法满足这种需求,因此不具备分布事务处理能力。

  • 本地事务的隔离的最小单位由资源管理器决定。

分布式事务

分布式事务涉及几个主要的核心概念和要素,它们对于实现分布式系统的一致性和可靠性至关重要。

  • 全局事务:全局事务由事务管理器全局管理,涉及多个参与者和资源。全局事务的管理确保了所有相关操作的一致性和正确性。
  • 事务管理器:事务管理器是负责管理全局事务状态和参与的资源的组件。它协调并监控所有参与者的操作,并确保所有资源的一致性提交或回滚。
  • 事务协议(TX协议):TX协议是应用或应用服务器与事务管理器之间的接口协议。它定义了事务的开始、提交和回滚等操作,并提供了协调和通信机制,以确保分布式环境下的事务一致性。
  • 分布式事务协议(XA协议):XA协议是全局事务管理器与资源管理器之间的接口协议。它定义了全局事务管理器如何与资源管理器进行通信,并协调资源的提交或回滚操作。

XA协议提供了一种标准化的方式来实现分布式事务的一致性和可靠性。

全局事务(DTP模型)— 标准分布式事务

以下是对这段内容的润色和优化:

  • AP(Application Program):应用程序,即使用分布式事务处理(DTP)的程序。它通过与事务管理器进行交互来对资源进行控制和操作。
  • RM(Resource Manager):资源管理器,可以是数据库管理系统(DBMS)或消息中间件等。应用程序通过资源管理器来控制和管理实际资源,并且这些资源必须实现XA定义的接口。
  • TM(Transaction Manager):事务管理器,负责协调和管理事务的执行。它提供给应用程序编程接口(API),以便应用程序能够定义和管理事务,并与资源管理器进行交互。事务管理器控制全局事务的生命周期,协调各个资源管理器的操作。

事务管理器和资源管理器在分布式事务处理中扮演着关键角色。事务管理器负责整个事务的管理和协调,而资源管理器负责实际资源的控制和管理。

全局事务(DTP模型) — XA

XA是由X/Open组织提出的用于分布式事务的规范。它主要定义了全局事务管理器(TM)和局部资源管理器(RM)之间的接口。许多主流的关系型数据库产品都已经实现了XA接口。

XA规范提供了一种标准化的方式来实现分布式事务的管理和协调。通过TM和RM之间定义的接口,可以实现跨多个资源管理器的全局事务的操作和控制。

XA接口的实现
  • XA接口是双向的系统接口,在事务管理器(TM)以及一个或多个资源管理器(RM)之间形成通信桥梁。
  • XA之所以需要引入事务管理器是因为,在分布系统中,从理论上讲两台机器理论上无法达到一致的状态,需要引入一个单点进行协调。
  • 由全局事务管理器管理和协调的事务,可以跨越多个资源(如数据库或MS队列)和进程。全局事务管理器一股使用XA二阶段提交协议与数据库进行交互。
XA的2PC机制

两阶段提交协议(Two-phase commit protocol)是XA用于在全局事务中协调多个资源的机制。

TM和RM间采取两阶段提交(Two Phase Commit)的方案来解决一致性问题,两阶段提交需要一个协调者(TM)来掌控所有参与者节点(RM)的操作结果并且指引这些节点是否需要最终提交。

2PC机制的分析

准备操作与ACID状态控制

  • A:准备后,仍可提交与回滚
  • C:准备时,一致性检查必须OK
  • I :准备后,事务结果仍然只在事务内可见
  • D:准备后,事务结果已经持久
2PC机制的局限
  • 协议成本:在分布式事务中,准备操作是否必需是一个重要的考虑因素。
  • 准备阶段的特性成本:准备阶段所需的成本是必须考虑的。
  • 全局事务状态的持久成本:保持全局事务状态的持久性有一定的成本。
  • 多个潜在故障点所带来的脆弱性:分布式系统中存在多个潜在故障点,可能会增加系统的脆弱性。
  • 准备阶段后、提交前发生故障可能会引发一系列难以解决的隔离和恢复问题。

JavaEE平台中的分布式事务实现

  • JTA(Java Transaction API):面向应用程序、应用服务器和资源管理器的高级事务接口。它提供了一套用于管理和协调事务的方法和接口。
  • JTS(Java Transaction Service):JTA事务管理器的实现标准,向上支持TA(Transaction Application),向下通过CORBA OTS(Common Object Request Broker Architecture Object Transaction Service)实现跨事务域的互操作性。
  • EJB(Enterprise JavaBeans):一种基于组件的应用程序编程模型,通过声明式事务管理进一步简化事务应用的编程。它提供了一种轻松管理事务的方式,使开发人员能够专注于业务逻辑的实现。
  • JTA和JTS为开发人员提供了面向应用程序和应用服务器的高级事务接口,使得事务的管理变得更加简单和灵活。而EJB作为一种应用程序编程模型,通过声明式事务管理进一步简化了事务应用的开发。
优点
  • 简单一致的编程模型
  • 跨域分布处理的ACID保证
局限
  • DTP模型本身的局限

刚性事务解决方案的利弊

  • 优点:严格的ACID
  • 缺点:效率较低(不适用于微服务架构)
  • 在全局事务模式下,全局事务管理器(TM)通过XA接口使用二阶段提交协议(2PC)与资源层(如数据库)进行交互。使用全局事务时,数据会在整个事务期间被锁定,直到全局事务结束。
  • 2PC采用反可伸缩模式,在事务处理过程中,参与者需要一直持有资源直到整个分布式事务结束。随着业务规模的增大,2PC的局限性变得越来越明显,系统的可伸缩性会受到影响。
  • 与本地事务相比,使用XA协议的系统开销相当大,因此在考虑是否真正需要分布式事务时应该谨慎。此外,只有支持XA协议的资源才能参与分布式事务。

柔性事务

Base协议

  • BA(Basic Availability):基本业务可用性,即系统在面对分区失败时仍然能够保持部分可用状态。
  • S(Soft State):柔性状态,允许系统中的状态在一段短暂时间内不同步,即允许异步的状态变更。
  • E(Eventual Consistency):最终一致性,在一定时间内保证数据最终达到一致状态,尽管不是实时一致。
  • 原子性(A)和持久性(D)是不可或缺的要求,必须得到严格保障。为了满足可用性、性能和服务降级的需求,需要降低一致性(C)和隔离性(I)的要求。

酸碱平衡(ACID-BASE Balance)

CAP协议

定理:对于共享数据系统,最多只能同时满足CAP中的两个要素,无法同时满足三个要素。每种组合都有适用的场景。 真实的系统应该是ACID和BASE的混合体。ACID提供了强一致性和可靠性,适用于那些对数据一致性要求高的业务场景。而BASE则提供了更高的可用性和分区容错性,适用于对数据一致性要求相对较低的场景。

不同类型的业务应该根据其特点进行区别对待。对于核心的、对数据一致性要求严格的业务,应该优先考虑ACID特性。而对于非核心业务或对实时一致性要求不高的业务,可以灵活选择BASE特性来提高可用性和性能。

柔性事务中的服务模式

可查询操作

服务操作的可标识性
  • 服务操作具有全局唯一标识
  • 可以使用业务单据号(如订单号)
  • 使用系统分配的操作流水号(如支付记录流水号)
  • 使用操作资源的组合组合标识(如商户号+商户订单号)
  • 操作有唯一的、确定的时间(约定以谁的时间为准)

幂等操作

重复调用多次产生的业务结果与调用一次产生的业务结果相同

幂等性(ldempotenty)

scss

复制代码

f(f(x))  =  f(x)
实现方式
  • 通过业务操作本身实现幂等性
  • 系统缓存所有请求与处理结果
  • 检测到重复请求之后,自动返回之前的处理结果

TCC操作

在分布式事务中执行业务操作。首先,在Try阶段完成业务检查和预留资源。在确认无误后,执行业务操作并在Confirm阶段使用预留的资源。如果需要取消操作,可以在Cancel阶段释放已预留的资源。

Try(尝试):尝试执行业务操作
  • 完成所有业务检查,确保数据的一致性。
  • 预留必要的业务资源,以保证准隔离性。
Confirm(确认):确认执行业务操作
  • 真正执行业务操作。
  • 无需再进行业务检查。
  • 只使用在Try阶段预留的业务资源。
  • Confirm操作要满足幂等性。
Cancel(取消):取消执行业务操作
  • 释放在Try阶段预留的业务资源。
  • Cancel操作要满足幂等性。

TCC操作中的Confirm操作和Cancel操作,其实也可以看作是补偿操作

与2PC协议比较
  • 位于业务服务层而非资源层,使得分布式事务的控制逻辑更加灵活。
  • 不需要单独的准备(Prepare)阶段,简化了事务的处理流程。
  • Try操作兼备资源操作和准备能力,能够在一步完成业务操作和资源锁定。
  • Try操作允许根据具体业务需求灵活选择业务资源的锁定粒度,以满足不同的场景需求。
  • 较高的开发成本,因为需要对业务逻辑进行详细的设计和实现。

与传统的2PC协议相比,这种基于Try-Confirm-Cancel模式的分布式事务处理方式在业务服务层进行控制,提供了更大的灵活性和可定制性。

同时,由于没有独立的准备阶段,整个流程更加简化。然而,这种方式也可能带来更高的开发成本,因为需要对业务逻辑进行更详细的设计和实现。

可补偿操作

一种基于补偿的分布式事务处理方式。在Do阶段执行实际的业务操作,并对外提供可见的业务执行结果。如果发生错误或异常情况,通过Compensate(业务补偿)操作来反转或纠正之前的业务操作结果。补偿操作必须具备幂等性,以确保多次执行不会产生不一致的结果。

Do(真正执行业务)

执行实际的业务操作。

  • 完成业务处理。
  • 业务执行结果对外可见。
Compensate(业务补偿)

补偿(或部分补偿)正向业务操作的结果。

  • 抵销或修正之前执行的正向业务操作的结果。
  • 补偿操作必须满足幂等性要求。
约束
  • 补偿在业务上是可行的,即存在补偿措施可以修复或抵消业务操作的结果。
  • 风险和成本由于业务执行结果未隔离或补偿不完整带来的风险和成本应该是可以控制的。

可靠消息最终一致(异步确保型)

  1. 在业务处理服务提交业务事务之前,向实时消息服务发送消息请求,实时消息服务只记录消息数据而不实际发送。在业务事务提交后,业务处理服务向实时消息服务确认发送。
  2. 只有在收到确认发送指令后,实时消息服务才真正发送消息。
  3. 在业务事务回滚后,业务处理服务向实时消息服务取消发送。然后,消急状态确认系统定期检查未确认发送或回滚发送的消息,并向业务处理服务询问消息状态。根据消急ID或消息内容,业务处理服务确定消息是否有效。

约束

被动方的处理结果不影响主动方的处理结果,被动方的消息处理操作是幂等的,确保业务数据可靠的前提下,实现业务数据的最终一致。

用到的服务模式

可查询操作、幂等操作

成本

  • 建设可靠的消急系统的成本,兼容所有实现)MS标准的MQ中间件
  • 一次消息的发送需要两次请求,因此业务处理服务需要实现消息状态回查接口。

优点和适用范围

  • 消息数据独立存储,降低了业务系统与消息系统之间的耦合。
  • 对于对最终一致性时间敏感性较高的场景,降低了业务被动方实现的成本。

最大努力通知

在业务活动的主动方完成业务处理后,向业务活动的被动方发送消息。允许消息丢失。业务活动的被动方根据定时策略,向业务活动的主动方查询,以恢复可能丢失的业务消息。

被动方的处理结果不会影响主动方的处理结果,适用于对业务最终一致性的时间敏感度较低的场景,特别是跨企业的业务活动。

这种实现方式允许业务活动的主动方发送消息给被动方,但允许消息的丢失。被动方根据定时策略进行查询,以确保消息的完整性。适用于对业务最终一致性的时间敏感度较低的场景,特别是跨企业的业务活动。


总结

常用的分布式事务解决方案包括:

  • 刚性事务:
  • 全局事务:也称为标准的分布式事务,涉及多个参与者和资源的一致性操作。
  • 柔性事务:
  • 可靠消息最终一致:通过异步确保型机制,使用可靠消息传递保证数据最终一致性。
  • TCC(两阶段型、补偿型):通过两阶段提交和补偿机制来实现分布式事务的一致性。
  • 最大努力通知:通过非可靠消息机制和定期校对来尽力保证最终一致性。
  • 纯补偿型:通过纯补偿机制处理分布式事务,可能无法保证100%的一致性。

这些分布式事务解决方案都是在不同的场景下应用的,根据具体需求选择合适的方案可以提高系统的可靠性和性能。请注意,每种方案都可能存在一定的限制和适用性,需要根据业务需求进行权衡和选择。

结论:分布式系统中,最重要的是满足业务需求,而不是追求抽象、绝对的系统特性。

相关文章
|
4天前
|
存储 Dubbo Java
分布式 RPC 底层原理详解,看这篇就够了!
本文详解分布式RPC的底层原理与系统设计,大厂面试高频,建议收藏。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
分布式 RPC 底层原理详解,看这篇就够了!
|
21天前
|
程序员
后端|一个分布式锁「失效」的案例分析
小猿最近很苦恼:明明加了分布式锁,为什么并发还是会出问题呢?
30 2
|
1月前
|
分布式计算 Hadoop 网络安全
Hadoop-08-HDFS集群 基础知识 命令行上机实操 hadoop fs 分布式文件系统 读写原理 读流程与写流程 基本语法上传下载拷贝移动文件
Hadoop-08-HDFS集群 基础知识 命令行上机实操 hadoop fs 分布式文件系统 读写原理 读流程与写流程 基本语法上传下载拷贝移动文件
30 1
|
1月前
|
存储 机器学习/深度学习 缓存
Hadoop-07-HDFS集群 基础知识 分布式文件系统 读写原理 读流程与写流程 基本语法上传下载拷贝移动文件
Hadoop-07-HDFS集群 基础知识 分布式文件系统 读写原理 读流程与写流程 基本语法上传下载拷贝移动文件
44 1
|
1月前
|
存储 缓存 数据处理
深度解析:Hologres分布式存储引擎设计原理及其优化策略
【10月更文挑战第9天】在大数据时代,数据的规模和复杂性不断增加,这对数据库系统提出了更高的要求。传统的单机数据库难以应对海量数据处理的需求,而分布式数据库通过水平扩展提供了更好的解决方案。阿里云推出的Hologres是一个实时交互式分析服务,它结合了OLAP(在线分析处理)与OLTP(在线事务处理)的优势,能够在大规模数据集上提供低延迟的数据查询能力。本文将深入探讨Hologres分布式存储引擎的设计原理,并介绍一些关键的优化策略。
97 0
|
1月前
|
NoSQL Java Redis
太惨痛: Redis 分布式锁 5个大坑,又大又深, 如何才能 避开 ?
Redis分布式锁在高并发场景下是重要的技术手段,但其实现过程中常遇到五大深坑:**原子性问题**、**连接耗尽问题**、**锁过期问题**、**锁失效问题**以及**锁分段问题**。这些问题不仅影响系统的稳定性和性能,还可能导致数据不一致。尼恩在实际项目中总结了这些坑,并提供了详细的解决方案,包括使用Lua脚本保证原子性、设置合理的锁过期时间和使用看门狗机制、以及通过锁分段提升性能。这些经验和技巧对面试和实际开发都有很大帮助,值得深入学习和实践。
太惨痛: Redis 分布式锁 5个大坑,又大又深, 如何才能 避开 ?
|
3月前
|
NoSQL Redis
基于Redis的高可用分布式锁——RedLock
这篇文章介绍了基于Redis的高可用分布式锁RedLock的概念、工作流程、获取和释放锁的方法,以及RedLock相比单机锁在高可用性上的优势,同时指出了其在某些特殊场景下的不足,并提到了ZooKeeper作为另一种实现分布式锁的方案。
110 2
基于Redis的高可用分布式锁——RedLock
|
3月前
|
缓存 NoSQL Java
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解分布式情况下如何添加分布式锁 【续篇】
这篇文章是关于如何在SpringBoot应用中整合Redis并处理分布式场景下的缓存问题,包括缓存穿透、缓存雪崩和缓存击穿。文章详细讨论了在分布式情况下如何添加分布式锁来解决缓存击穿问题,提供了加锁和解锁的实现过程,并展示了使用JMeter进行压力测试来验证锁机制有效性的方法。
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解分布式情况下如何添加分布式锁 【续篇】
|
7天前
|
NoSQL Redis
Redis分布式锁如何实现 ?
Redis分布式锁通过SETNX指令实现,确保仅在键不存在时设置值。此机制用于控制多个线程对共享资源的访问,避免并发冲突。然而,实际应用中需解决死锁、锁超时、归一化、可重入及阻塞等问题,以确保系统的稳定性和可靠性。解决方案包括设置锁超时、引入Watch Dog机制、使用ThreadLocal绑定加解锁操作、实现计数器支持可重入锁以及采用自旋锁思想处理阻塞请求。
40 16
|
1月前
|
缓存 NoSQL Java
大数据-50 Redis 分布式锁 乐观锁 Watch SETNX Lua Redisson分布式锁 Java实现分布式锁
大数据-50 Redis 分布式锁 乐观锁 Watch SETNX Lua Redisson分布式锁 Java实现分布式锁
59 3
大数据-50 Redis 分布式锁 乐观锁 Watch SETNX Lua Redisson分布式锁 Java实现分布式锁