今天是:
带着程序的旅程,每一行代码都是你前进的一步,每个错误都是你成长的机会,最终,你将抵达你的目的地。
title

事务

1.什么是事务
 

事务(Transaction)是指数据库管理系统(DBMS)中的一个操作单位,它由一个或多个数据库操作(例如插入、更新、删除等)组成。事务的目的是确保数据库的一致性、完整性和持久性。

事务具有以下四个特性,通常被称为 ACID 特性:

  1. 原子性(Atomicity): 事务被视为一个不可分割的原子操作。它要么完全执行,要么完全不执行。如果在事务执行过程中发生故障,系统将回滚事务,使数据回到事务开始前的状态。

  2. 一致性(Consistency): 事务的执行使数据库从一个一致性状态转换到另一个一致性状态。在事务开始和结束时,数据库必须满足特定的一致性规则,以保证数据的有效性和完整性。

  3. 隔离性(Isolation): 并发执行的多个事务之间应该相互隔离,以防止互相干扰。一个事务在提交之前,其所做的修改对其他事务是不可见的,从而避免了数据的混乱状态。

  4. 持久性(Durability): 一旦事务提交,其对数据库的修改将会被永久保存,即使在系统故障的情况下也不会丢失。系统需要将事务的修改记录在持久存储介质中,如硬盘。

通过保持事务的 ACID 特性,数据库可以确保在任何情况下都能维护数据的完整性和一致性。例如,当多个用户同时访问数据库时,事务可以防止数据损坏或丢失。

2.本地事务
 

本地事务(Local Transaction)是指在单个数据库上执行的事务,而不涉及跨多个数据库或系统的操作。本地事务 是指仅操作单一事务资源的、不需要全局事务管理器进行协调的事务。适用于单个服务使用单个数据源的场景。

本地事务中原子性和持久性的实现

由于内存数据写入磁盘数据不是原子的,中间可能会有系统崩溃或数据库崩溃的情况,无法预知崩溃的情况, 所以只能在发送故障前记录对数据的操作,这样在故障发生后才可以恢复数据或执行回滚操作。这个记录就是提交日志Commit Logging 。

Commit Logging 保障数据持久性、原子性的原理并不难理解:首先,日志一旦成功写入 C ommit Record,那整个事务就是成功的,即使真正修改数据时崩溃了,重启后根据已经写 入磁盘的日志信息恢复现场、继续修改数据即可,这保证了持久性;其次,如果日志没有 成功写入 Commit Record 就发生崩溃,那整个事务就是失败的,系统重启后会看到一部分 没有 Commit Record 的日志,那将这部分日志标记为回滚状态即可,整个事务就像完全没 好有发生过一样,这保证了原子性。

提交日志演变未两种日志

Undo Log,RedoLog 。 当变动数据写入磁盘前,必须先记录 Undo Log,注明修 改了哪个位置的数据、从什么值改成什么值,等等。以便在事务回滚或者崩溃恢复时根据

Undo Log 对提前写入的数据变动进行擦除。Undo Log 现在一般被翻译为“回滚日志”,此 前记录的用于崩溃恢复时重演数据变动的日志就相应被命名为 Redo Log,一般翻译为“重 做日志”。 日志的查找

  • 分析阶段(Analysis):该阶段从最后一次检查点(Checkpoint,可理解为在这个点之 前所有应该持久化的变动都已安全落盘)开始扫描日志,找出所有没有 End Record 的 事务,组成待恢复的事务集合,这个集合至少会包括 Transaction Table 和 Dirty Page Ta ble 两个组成部分。
  • 重做阶段(Redo):该阶段依据分析阶段中产生的待恢复的事务集合来重演历史(Rep eat History),具体操作为:找出所有包含 Commit Record 的日志,将这些日志修改的 数据写入磁盘,写入完成后在日志中增加一条 End Record,然后移除出待恢复事务集 合。
  • 回滚阶段(Undo):该阶段处理经过分析、重做阶段后剩余的恢复事务集合,此时剩 下的都是需要回滚的事务,它们被称为 Loser,根据 Undo Log 中的信息,将已经提前 写入磁盘的信息重新改写回去,以达到回滚这些 Loser 事务的目的。

本地事务隔离性的实现

隔离性就需要通过锁来实现了。隔离性保证了每个事务各自读、写的数据互 相独立,不会彼此影响。 数据库中的三种锁

  • 写锁(Write Lock,也叫作排他锁,eXclusive Lock,简写为 X-Lock):如果数据有加写 锁,就只有持有写锁的事务才能对数据进行写入操作,数据加持着写锁时,其他事务不 能写入数据,也不能施加读锁。
  • 读锁(Read Lock,也叫作共享锁,Shared Lock,简写为 S-Lock):多个事务可以对同 一个数据添加多个读锁,数据被加上读锁后就不能再被加上写锁,所以其他事务不能对 该数据进行写入,但仍然可以读取。对于持有读锁的事务,如果该数据只有它自己一个 事务加了读锁,允许直接将其升级为写锁,然后写入数据。
  • 范围锁(Range Lock):对于某个范围直接加排他锁,在这个范围内的数据不能被写 入。

事务的隔离级别 有

  1. 读未提交(Read Uncommitted): 这是最低的隔离级别。在该级别下,一个事务可以读取另一个事务尚未提交的数据。这可能导致脏读(Dirty Read),即读取了尚未确认的数据,而这些数据可能在事务回滚时被撤销。

  2. 读已提交(Read Committed): 在这个级别下,一个事务只能读取已经提交的数据。这避免了脏读,但可能导致不可重复读(Non-repeatable Read),即在同一个事务中,对同一数据进行多次读取,但得到的结果可能不同。。因为读提交隔离级别下,查询完之后,读锁会立刻释放。

  3. 可重复读(Repeatable Read): 在这个级别下,一个事务在其生命周期内多次读取同一数据,得到的结果应该是一致的。其他事务不能修改被读取的数据,但可能会插入新数据。这避免了脏读和不可重复读,但可能导致幻读(Phantom Read),即一个事务在多次查询中看到了不同数量的行。 但是在mysql中可重复读总一个事务并不会读取到另一个事务以提交的事务,这是因为下面要说的MVCC的存在。

  4. 串行化(Serializable): 这是最高的隔离级别,也是最严格的。在该级别下,事务被顺序执行,一个事务的操作完全独立于其他事务。这避免了脏读、不可重复读和幻读,但可能会影响系统的并发性能。

 


脏读和幻读的区别

  • 脏读是指一个事务读取了另一个事务尚未提交的数据,可能导致事务基于错误的数据做出决策。
  • 幻读是指在同一个事务中,两次相同的查询由于其他事务的插入、更新或删除操作而返回了不同的结果。
  • 脏读也可以认为是幻读的一种情况,因为也可能读取到其他事务插入还未提交的数据,从这个意思上来说也是幻读。脏读会在错的数据上做修改,而幻读是已提交的数据,可能导致插入或更新时的错误。

mvcc


MVCC通过维护数据的多个版本来解决这些问题。每个事务都可以看到数据的一个特定版本,这个版本是在事务开始时数据库中存在的。当事务进行修改时,它实际上是创建了一个新版本的数据,而不是直接在现有数据上进行修改。这意味着其他事务仍然可以访问旧版本的数据,从而避免了锁定和冲突。

ReadView

ReadView可以理解为数据库中某一个时刻所有未提交事务的快照。ReadView有几个重要的参数:

字段 说明 可见性说明
m_low_limit_id 尚未分配的最小事务id >=它的, 都不可见
m_up_limit_id 最小活动未提交事务id <它的, 都可见
m_creator_trx_id 创建readview的事务id =它的, 都可见
m_ids 当前系统中那些活跃(未提交)的读写事务ID, 它数据结构为一个List。  

所以当创建ReadView时,可以知道这个时间点上未提交事务的所有信息。

隐藏列

InnoDB存储引擎中,它的聚簇索引记录中都包含两个必要的隐藏列,分别是:

  • DB_TRX_ID :6 byte,插入或更新行的最后一个事务ID. (解读:用于MVCC的ReadView判断事务id) 此外, 删除在内部被视为更新,其中行中的一个特殊位被设置为将其标记为已删除.
  • DB_ROLL_PTR:7 byte,回滚指针. (解读:用于MVCC中指向undo log记录) 指向已写入回滚段(rollback segment)的一条undo log记录, 记录着行(row)更新前的副本.
  • DB_ROW_ID:6 byte,隐藏的自增 ID. (解读:对于MVCC可忽略该字段) 如果InnoDB自动生成聚集索引, 则索引包含这个行ID值. 否则, DB_ROW_ID列不会出现在任何索引中.

通过隐藏列,基于版本号叫undolog日志形成一个链表。然后根据readview查询当前事务可以读取的版本数据来实现可重复度。

  • READ COMMITTED —— 每次读取数据前都生成一个ReadView
  • REPEATABLE READ —— 在第一次读取数据时生成一个ReadView

如下是事务A可重复度的例子

3.全局事务

资源本地事务允许我们在单个资源内执行多个操作,作为一个统一的整体。然而,我们经常处理跨越多个资源的操作。例如,在两个不同的数据库或一个数据库和一个消息队列中的操作。在这种情况下,资源内的本地事务支持是不够的。

在这些情况下,我们需要一个全局机制来标记跨越多个参与资源的事务。XA 规范就是这样一种规范,它定义了一个事务管理器来控制跨多个资源的事务。Java 在符合 XA 规范的情况下,通过 JTA 和 JTS 组件为分布式事务提供了相当成熟的支持。

JTA 最主要的两个接口 是: 事务管理器的接口: javax.transaction.TransactionManager 。这套接口是给 Java EE

服务器提供容器事务(由容器自动负责事务管理)使用的,还提供了另外一套 javax.tr ansaction.UserTransaction 接口,用于通过程序代码手动开启、提交和回滚事务。 满足 XA 规范的资源定义接口: javax.transaction.xa.XAResource ,任何资源(JDB C、JMS 等等)如果想要支持 JTA,只要实现 XAResource 接口中的方法即可。

JTA 原本是 Java EE 中的技术,一般情况下应该由 JBoss、WebSphere、WebLogic 这些 Jav a EE 容器来提供支持,但现在Bittronix 、Atomikos 和JBossTM (以前叫 Arjuna)都 以 JAR 包的形式实现了 JTA 的接口,称为 JOTM(Java Open Transaction Manager),使 得我们能够在 Tomcat、Jetty 这样的 Java SE 环境下也能使用 JTA。

XA 将事务提交拆分成为两阶段过程

准备阶段:又叫作投票阶段,在这一阶段,协调者询问事务的所有参与者是否准备好提 交,参与者如果已经准备好提交则回复 Prepared,否则回复 Non-Prepared。这里所说 的准备操作跟人类语言中通常理解的准备并不相同,对于数据库来说,准备操作是在重 做日志中记录全部事务提交操作所要做的内容,它与本地事务中真正提交的区别只是暂

不写入最后一条 Commit Record 而已,这意味着在做完数据持久化后并不立即释放隔离 性,即仍继续持有锁,维持数据对其他非事务内观察者的隔离状态。

提交阶段:又叫作执行阶段,协调者如果在上一阶段收到所有事务参与者回复的 Prepar ed 消息,则先自己在本地持久化事务状态为 Commit,在此操作完成后向所有参与者发 送 Commit 指令,所有参与者立即执行提交操作;否则,任意一个参与者回复了 Non-P repared 消息,或任意一个参与者超时未回复,协调者将自己的事务状态持久化为 Abor t 之后,向所有参与者发送 Abort 指令,参与者立即执行回滚操作。对于数据库来说, 这个阶段的提交操作应是很轻量的,仅仅是持久化一条 Commit Record 而已,通常能够 快速完成,只有收到 Abort 指令时,才需要根据回滚日志清理已提交的数据,这可能是 相对重负载的操作。

两阶段非常显著的缺点:

单点问题:协调者在两段提交中具有举足轻重的作用,协调者等待参与者回复时可以有 超时机制,允许参与者宕机,但参与者等待协调者指令时无法做超时处理。一旦宕机的 不是其中某个参与者,而是协调者的话,所有参与者都会受到影响。如果协调者一直没 有恢复,没有正常发送 Commit 或者 Rollback 的指令,那所有参与者都必须一直等待。

性能问题:两段提交过程中,所有参与者相当于被绑定成为一个统一调度的整体,期间 要经过两次远程服务调用,三次数据持久化(准备阶段写重做日志,协调者做状态持久 化,提交阶段在日志写入 Commit Record),整个过程将持续到参与者集群中最慢的那 一个处理操作结束为止,这决定了两段式提交的性能通常都较差。

一致性风险:前面已经提到,两段式提交的成立是有前提条件的,当网络稳定性和宕机 恢复能力的假设不成立时,仍可能出现一致性问题。宕机恢复能力这一点不必多谈,19 85 年 Fischer、Lynch、Paterson 提出了“FLP 不可能原理 ”,证明了如果宕机最后不能 恢复,那就不存在任何一种分布式协议可以正确地达成一致性结果。该原理在分布式中 是与“CAP 不可兼得原理“齐名的理论。而网络稳定性带来的一致性风险是指:尽管提交 阶段时间很短,但这仍是一段明确存在的危险期,如果协调者在发出准备指令后,根据 收到各个参与者发回的信息确定事务状态是可以提交的,协调者会先持久化事务状态,

并提交自己的事务,如果这时候网络忽然被断开,无法再通过网络向所有参与者发出 C ommit 指令的话,就会导致部分数据(协调者的)已提交,但部分数据(参与者的)既 未提交,也没有办法回滚,产生了数据不一致的问题。

mysql内部两阶段实现,通过binlog作为协调器。

  1. 首先调用存储引擎的 prepare 接口 (两阶段准备阶段)
  2. 调用 TC_LOG 的 commit 接口写入binlog日志
  3. 调用存储引擎的 commit 接口 (两阶段提交阶段)

写redolog和binlog的三种情况

情况一:一阶段提交之后崩溃了,即写入 redo log,处于 prepare 状态 的时候崩溃了,此时:

由于 binlog 还没写,redo log 处于 prepare 状态还没提交,所以崩溃恢复的时候,这个事务会回滚,此时 binlog 还没写,所以也不会传到备库。

情况二:假设写完 binlog 之后崩溃了,此时:

redolog 中的日志是不完整的,处于 prepare 状态,还没有提交,那么恢复的时候,首先检查 binlog 中的事务是否存在并且完整,如果存在且完整,则直接提交事务,如果不存在或者不完整,则回滚事务。

情况三:假设 redolog 处于 commit 状态的时候崩溃了,那么重启后的处理方案同情况二。

三阶段提交

三段式提交把原本 的两段式提交的准备阶段再细分为两个阶段,分别称为 CanCommit、PreCommit,把提交 阶段改称为 DoCommit 阶段。

  1. 准备阶段(CanCommit): 在这个阶段,协调者(通常是事务管理器)向所有参与者(资源或子事务)发送询问,询问它们是否可以提交事务。参与者会检查它们自己的资源状态来决定是否可以提交。如果所有参与者都同意,那么协调者会继续进入下一个阶段。

  2. 预提交阶段(PreCommit): 在这个阶段,协调者要求所有参与者执行事务的预提交操作。参与者执行预提交并在本地记录提交请求,但仍然不对外部环境(如数据库)做出永久性的改变。如果所有参与者成功执行预提交,那么协调者将进入最后一个阶段。

  3. 提交阶段(DoCommit): 在这个阶段,协调者向所有参与者发送最终的提交请求。参与者执行真正的提交操作,将事务的改变永久地应用到各自的资源中。如果所有参与者成功提交,那么全局事务就成功完成。如果有任何问题发生,比如参与者中的某个资源无法提交,协调者将发送回滚请求,参与者将回滚之前的预提交操作。

4.分布式事务

分布式事务就是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。通常它会在由网络连接的不同节点之间进行协调,但也可能横跨单个服务器上的多个数据库。

分布式与集群 

  1. 分布式(Distributed): 分布式系统是由多台独立的计算机或节点组成,这些计算机通过网络进行通信和协作。每个节点都可以独立运行,并且可以处理任务、存储数据等。分布式系统的目标是将工作分散到多个节点上,以提高系统的可伸缩性、容错性和性能。分布式系统可以包括分布式数据库、分布式文件系统、分布式计算等。在分布式系统中,不同节点之间通常会协调和协作,但它们可以是独立的物理设备。

  2. 集群(Cluster): 集群是由多个计算机(节点)组成的一个组,这些计算机通过高速网络连接在一起,并以协同方式工作。集群的目标是通过将多台计算机连接在一起,创建一个高性能、高可用性的系统,以共同处理任务和提供服务。在集群中,计算机可以协同工作,共享负载、存储和处理能力,以实现高性能和容错性。集群可以用于各种用途,包括网络服务、数据处理、高性能计算等。集群中的计算机通常是物理上相近的,并且通过特定的集群管理软件来进行协调。

CAP理论

  1. 一致性(Consistency):代表数据在任何时刻、任何分布式节点中所看到的都是符合预 期的。一致性在分布式研究中是有严肃定义、有多种细分类型的概念,以后讨论分布式 共识算法时,我们还会再提到一致性,那种面向副本复制的一致性与这里面向数据库状 态的一致性严格来说并不完全等同,具体差别我们将在后续分布式共识算法中再作探 讨。
  2. 可用性(Availability):代表系统不间断地提供服务的能力,理解可用性要先理解与其 密切相关两个指标:可靠性(Reliability)和可维护性(Serviceability)。可靠性使用平 均无故障时间(Mean Time Between Failure,MTBF)来度量;可维护性使用平均可修 复时间(Mean Time To Repair,MTTR)来度量。可用性衡量系统可以正常使用的时间 与总时间之比,其表征为:A=MTBF/(MTBF+MTTR),即可用性是由可靠性和可维护 性计算得出的比例值,譬如 99.9999%可用,即代表平均年故障修复时间为 32 秒。
  3. 分区容忍性(Partition Tolerance):代表分布式环境中部分节点因网络原因而彼此失 联后,即与其他节点形成“网络分区”时,系统仍能正确地提供服务的能力。

BASE理论

  1. 基本可用性(Basically Available): 在分布式系统中,系统应该保证在面对故障或部分失效时仍能保持基本的可用性,即系统能够继续处理请求并提供某种程度的服务,尽管可能无法提供完整的功能。

  2. 软状态(Soft State): 分布式系统中的各个节点可能由于网络延迟、通信失败或其他原因而存在状态不一致的情况。在 BASE 理论中,允许系统处于一段时间内的“软状态”,即在状态同步之间可能存在短暂的不一致性,但最终会达到一致状态。

  3. 最终一致性(Eventual Consistency): BASE 理论认为,分布式系统中的一致性不需要实时保持,而是在一段时间内最终达到一致状态。即使在数据的复制和同步过程中存在延迟,系统最终会在全局范围内达到一致状态。

分布式事务的实现

分布式事务的实现方式有,可靠事件队列,前面提到的2PC,3PC.还有TCC和Saga事务。具体实现见 seata xa实现原理 

 

分享到:

专栏

类型标签

网站访问总量