当前位置: 首页 > news >正文

数据一致性问题剖析与实践(二)——单机事务的一致性问题

一、前言

对问题定义进行了扩展,是一个综合性问题,也会涉及竞态条件竞争,冗余数据存储。

事务的起源来自于数据库,其最重要的定义就是,要么全部成功执行,要么全部不执行,保证安全的状态转化。

之前我们讨论了几种场景的一致性问题

  • 冗余数据存储中的一致性问题
  • 分布式共识中的一致性问题

本文将围绕单机事务中的一致性问题展开讨论。

二、事务是什么?

2.1 本质

数据库事务的本质是一组数据库操作的集合,这些操作要么全部成功执行,要么全部不执行,以保证数据库从一个一致性状态转换到另一个一致性状态

事务这个概念在业务逻辑中非常常见,有非常多的实际场景需要。

2.2 事务特性 ——ACID

单机事务的 ACID 特性,是保障数据正确性与一致性的基础准则

  • 原子性(Atomicity):事务被视为一个不可分割的整体,所有操作要么全部成功提交,要么全部失败回滚。例如在银行转账中,从账户 A 扣款与向账户 B 入账必须同时完成,若扣款成功但入账失败,整个事务需回滚,确保资金不会凭空消失或增加 。

  • 隔离性(Isolation):多个并发事务之间相互隔离,互不干扰。不同隔离级别(读未提交、读已提交、可重复读、串行化)定义了事务间对数据访问的可见范围,避免脏读、不可重复读和幻读等问题 。

    其本质是控制数据的访问范围,在并发场景下,实现不同隔离级别下的“对外一致性”

  • 持久性(Durability):一旦事务提交成功,其对数据的修改将永久保存,即使系统出现故障(如断电、宕机)也不会丢失。银行交易完成后,账户余额的变更会持久化存储,确保数据的可靠性 。

  • 一致性(Consistency):事务执行前后,数据需从一个合法状态转换到另一个合法状态。如电商下单时,库存数量必须与订单数量保持逻辑一致,不能出现超卖现象,以维持业务规则的正确性 。

只有保证了原子性、隔离性、持久性的前提下,才能实现一致性,一致性是事务的目的。

三、单机事务中的一致性问题

以mysql为例

3.1 隔离性

隔离性是确保不同事务之间相互隔离、互不干扰,在并发执行时,每个事务都能如同在单线程环境下一样独立地运行,不受其他事务的影响。

其本质是控制数据的访问范围,在并发场景下,实现不同隔离级别下的“对外一致性”

3.1.1 产生场景

  1. 脏读:当一个事务读取到另一个未提交事务修改的数据时,就会发生脏读。例如,事务 A 对某条数据进行了修改,但尚未提交,此时事务 B 读取了这条被修改但未提交的数据,若事务 A 随后回滚了修改,那么事务 B 读取到的数据就是无效的,这就是脏读现象。在银行系统中,如果一个转账事务正在处理(未提交),另一个查询事务读取了转账过程中的临时余额,就可能出现脏读问题。
脏读场景
修改数据,未提交
读取数据
回滚修改
数据
事务 A
事务 B
  1. 不可重复读:在同一事务中,多次读取同一数据却得到不同的结果,原因是其他事务在此期间对该数据进行了修改并提交。比如,事务 A 先读取了某客户的账户余额,然后其他事务 B 对该账户进行了存款操作并提交,当事务 A 再次读取该账户余额时,得到的结果与第一次不同,这就产生了不可重复读的问题。
不可重复读场景
第一次读取数据
修改数据并提交
第二次读取数据
数据
事务 A
事务 B
  1. 幻读:在一个事务中执行查询操作时,由于其他事务插入或删除了符合查询条件的数据,导致该事务再次执行相同查询时得到了不同的结果集。例如,事务 A 查询某类商品的库存数量,然后事务 B 插入了一些该类商品的库存记录并提交,当事务 A 再次查询时,发现库存数量增加了,就好像出现了 “幻觉”,这就是幻读现象。

3.1.2 Mysql中的事务隔离级别

  • 读未提交(Read Uncommitted)级别最低,几乎不提供隔离保证,容易出现脏读、不可重复读和幻读;
  • 读已提交(Read Committed)可以避免脏读,但可能会出现不可重复读和幻读;
  • 可重复读(Repeatable Read)是 MySQL 的默认隔离级别,它可以避免脏读和不可重复读,但无法解决幻读;
  • 串行化(Serializable)是最高的隔离级别,它通过强制事务串行执行,完全避免了脏读、不可重复读和幻读,但会严重影响并发性能。
隔离级别设置
读已提交
读未提交
可重复读
串行化

3.1.3 解决范式

  1. 读屏障:通过控制读取的逻辑(比如读版本快照、还是读现在的数据)来实现对外的一致性。
    MySQL 提供了不同的事务隔离级别来解决上述问题,其中最主要的机制就是MVCC(Multiversion Concurrency Control),本质是一种快照读,通过自增的事务id来判断读哪个版本的快照数据,并通过redo log “回溯”返回对应的数据快照。
  2. 使用锁机制控制并发:本质是细粒度维度(如数据行、数据范围)去串行化写操作,来保证数据写的正确性
    在mysql中,如共享锁(S 锁)、排他锁(X 锁)和间隙锁。
    • 共享锁允许其他事务读取数据,但阻止其他事务修改数据;
    • 排他锁则完全阻止其他事务对数据的读写操作。例如,当一个事务需要对数据进行修改时,可以先获取排他锁,确保在修改期间其他事务无法干扰,从而保证数据的一致性。
    • 间隙锁,间隙锁主要用于解决幻读问题,它锁住的不是具体的数据行,而是数据的范围。当一个事务使用间隙锁锁定了某个数据范围后,其他事务无法在该范围内插入新的数据,从而避免了幻读现象的发生。
锁机制
获取共享锁
获取共享锁
尝试获取排他锁,等待
释放共享锁
获取排他锁
数据
事务 A
事务 B
事务 C

3.2 原子性

要么一起成功,要么一起失败!

3.2.1 产生场景

  1. 系统崩溃:在事务执行过程中,如果系统突然崩溃(如硬件故障、操作系统崩溃等),可能导致事务中的部分操作已经执行,而部分操作未执行。例如,在一个数据库更新事务中,已经完成了对某些表的插入操作,但在执行更新另一些表的操作时系统崩溃,这就破坏了事务的原子性。
  2. 软件错误:应用程序中的错误(如代码逻辑错误、异常未处理等)可能导致事务无法完整执行。比如,在一个涉及多个数据库操作的事务中,由于代码中的一个逻辑错误,导致在执行某个操作时抛出异常,使得后续操作无法继续进行,从而破坏了事务的原子性。
  3. 资源不足:当事务执行需要的资源(如数据库连接、内存等)不足时,可能无法完成所有操作。例如,在一个批量插入数据的事务中,由于数据库连接池耗尽,导致部分数据插入成功,部分数据插入失败,破坏了事务的原子性。
  4. 业务主动回滚:在某些业务场景下,根据特定的业务规则或条件判断,即使事务尚未执行完毕,也需要主动进行回滚操作。例如,在电商系统的订单创建事务中,当系统检测到用户的账户余额不足支付订单金额时,即使订单创建过程中的部分操作(如生成订单号、记录订单基本信息)已经完成,也需要主动回滚整个事务,取消订单创建,以保证业务逻辑的正确性和数据的一致性。

3.2.2 解决范式

常规解法有两种思路——回滚&尽最大努力交付,但是在单机事务这个场景下,一般都采用回滚的思路。

  • 回滚机制

以 MySQL 为例,MySQL 中的 InnoDB 存储引擎通过事务日志(重做日志 redo log 和回滚日志 undo log)来实现事务的回滚。

  • 尽最大努力交付

3.3 持久性

3.3.1 背景

在单机情况下,持久化主要指内存和磁盘之间的同步策略,本质是性能和可靠性的权衡。

3.3.2 解决范式

核心思路就是把数据写入磁盘,但难点在于性能和可靠性之间的平衡,其中常见的解决策略就是lsm-tree(Log-Structured-Merge-Tree),通过将数据的变化转化为日志的变化,从而实现顺序写磁盘,提升磁盘写入性能。

在Mysql中,

  1. WAL(Write-Ahead Logging):InnoDB使用WAL来保证数据的持久性。所有修改操作首先写入到WAL日志中,然后才更新内存中的数据结构。
  2. Change Buffer:InnoDB使用Change Buffer来减少磁盘I/O。当有多个修改操作发生时,它们会先被记录在Change Buffer中,然后定期合并到SSTable中。
  3. Buffer Pool:InnoDB使用Buffer Pool来存储最近访问的数据页,从而减少磁盘I/O。

总结

单机事务中的一致性问题,通过原子性、隔离性和持久性这三大特性的协同保障得以实现。

原子性确保事务操作的完整性,避免部分成功部分失败的情况;

隔离性控制并发事务之间的相互影响,通过不同的隔离级别和并发控制手段,实现数据访问的一致性;

持久性则致力于将事务提交的数据可靠地存储到磁盘,在性能和可靠性之间寻求平衡。

以 MySQL 为代表的单机数据库系统,通过 MVCC、各种锁机制、事务日志、WAL、Change Buffer 和 Buffer Pool 等一系列技术手段,有效地解决了单机事务中的一致性问题,为各类应用提供了稳定、可靠的数据处理基础。

相关文章:

  • 数据为基:机器学习中数值与分类数据的处理艺术及泛化实践
  • MacOS中安装Python(homebrew,pyenv)
  • Stable Baselines3 结合 gym 训练 CartPole 倒立摆
  • 【教学类-102-17】蝴蝶三色图(用最大长宽作图,填入横板和竖版共16个WORD单元格模版大小,制作大小图)
  • Java 环境配置详解(Windows、macOS、Linux)
  • 【Leetcode 每日一题】1399. 统计最大组的数目
  • 第52讲:农业AI + 区块链——迈向可信、智能、透明的未来农业
  • 大模型框架技术演进与全栈实践指南
  • 1.5软考系统架构设计师:架构师的角色与能力要求 - 超简记忆要点、知识体系全解、考点深度解析、真题训练附答案及解析
  • Elasticsearch 报错 Limit of total fields [1000] has been exceeded
  • Postman忘记密码访问官网总是无响应
  • SpringCloud 微服务复习笔记
  • 第七篇:linux之基本权限、进程管理、系统服务
  • Linux[指令与权限]
  • Vm免安装直接使用虚拟机win7系统
  • 每日算法-250423
  • VR 全景看车的独特优势​
  • 从0到1掌握机器学习核心概念:用Python亲手构建你的第一个AI模型(超多代码+可视化)
  • 具身智能操作知识梳理与拓展
  • Springfox + Swagger 的完整配置及同类框架对比的详细说明
  • 苗旋已任民航局空管局局长、党委副书记
  • 漫游者秦龙,一生为经典画插图
  • 停止水资源共享、驱逐武官,印度对巴基斯坦宣布多项反制措施
  • 已有17个国家和国际组织、50多个国际科研机构加入国际月球科研站合作
  • 福特中国CFO:依然坚信中国市场,上海帮助公司吸引到人才
  • 首映|国家自博馆4D电影《海洋深深》:潜入深海向地球发问