数据库原理 - 序列3 - 事务是如何实现的? - Redo Log解析

6.5 事务实现原理之1:Redo Log

介绍事务怎么用后,下面探讨事务的实现原理。事务有ACID四个核心属性:
A:原子性。事务要么不执行,要么完全执行。如果执行到一半,宕机重启,已执行的一半要回滚回去。
C:一致性。各种约束条件,比如主键不能为空、参照完整性等。
I:隔离性。隔离性和并发性密切相关,因为如果事务全是串行的(第四个隔离级别),也不需要隔离。
D:持久性。这个很容易理解,一旦事务提交了,数据就不能丢。
在这四个属性中,D比较容易,C主要是由上层的各种规则来约束,也相对简单。而A和I牵涉并发问题、崩溃恢复的问题,将是讨论的重点。

说到事务的实现原理,会追溯到ARIES算法理论,ARIES(Algorithms for Recovery AndIsolation Expoliting Semantics)是20世纪90年代由IBM的几位研究员提出的一个算法集,主论文是ARIES: A TransactionRecovery Method Supporting Fine-Granularity Locking and Partial Rollbacks UsingWrite-Ahead Loggging。ARIES的思想影响深远,现代的关系型数据库(DB2、MySQL、InnoDB、SQL Server、Oracle)在事务实现的很多方面都吸收了该思想,在大学的教科书上如果讲到事务的实现,也都会介绍AREIS方法。
接下来,就以InnoDB为背景,分析事务的ACID其中的三个属性(A、I、D)是如何实现的。先从最简单的D开始(I/O问题),然后是A,最后讨论I。

6.5.1 Write-Ahead
一个事务要修改多张表的多条记录,多条记录分布在不同的Page里面,对应到磁盘的不同位置。如果每个事务都直接写磁盘,一次事务提交就要多次磁盘的随机I/O,性能达不到要求。怎么办呢?不写磁盘,在内存中进行事务提交。然后再通过后台线程,异步地把内存中的数据写入到磁盘中。但有个问题:机器宕机,内存中的数据还没来得及刷盘,数据就丢失了。
为此,就有了Write-aheadLog的思路:先在内存中提交事务,然后写日志(所谓的Write-ahead Log),然后后台任务把内存中的数据异步刷到磁盘。日志是顺序地在尾部Append,从而也就避免了一个事务发生多次磁盘随机I/O的问题。明明是先在内存中提交事务,后写的日志,为什么叫作Write-Ahead呢?这里的Ahead,其实是指相对于真正的数据刷到磁盘,因为是先写的日志,后把内存数据刷到磁盘,所以叫Write-Ahead Log。
内存操作数据 +Write-Ahead Log的这种思想非常普遍,后面讲LSM树的时候,还会再次提到这个思想。在多备份一致性中,复制状态机的模型也是基于此。
具体到InnoDB中,Write-Ahead Log是Redo Log。在InnoDB中,不光事务修改的数据库表数据是异步刷盘的,连Redo Log的写入本身也是异步的。如图6-7所示,在事务提交之后,Redo Log先写入到内存中的Redo Log Buffer中,然后异步地刷到磁盘上的Redo Log。
为此,InnoDB有个关键的参数innodb_flush_log_at_trx_commit控制Redo Log的刷盘策略,该参数有三个取值:
0:每秒刷一次磁盘,把Redo Log Buffer中的数据刷到Redo Log(默认为0)。
1:每提交一个事务,就刷一次磁盘(这个最安全)。
2:不刷盘。然后根据参数innodb_flush_log_at_timeout设置的值决定刷盘频率。
很显然,该参数设置为0或者2都可能丢失数据。设置为1最安全,但性能最差。InnoDB设置此参数,也是为了让应用在数据安全性和性能之间做一个权衡。

图6-7 Redo Log的异步刷盘示意图

6.5.2 Redo Log的逻辑与物理结构
知道了Redo Log的基本设计思想,下面来看Redo Log的详细结构。
从逻辑上来讲,日志就是一个无限延长的字节流,从数据库安装好并启动的时间点开始,日志便源源不断地追加,永无结束。
但从物理上来讲,日志不可能是一个永不结束的字节流,日志的物理结构和逻辑结构,有两个非常显著的差异点:
(1)磁盘的读取和写入都不是按一个个字节来处理的,磁盘是“块”设备,为了保证磁盘的I/O效率,都是整块地读取和写入。对于Redo Log来说,就是Redo Log Block,每个Redo Log Block是512字节。为什么是512字节呢?因为早期的磁盘,一个扇区(最细粒度的磁盘存储单位)就是存储512字节数据。
(2)日志文件不可能无限制膨胀,过了一定时期,之前的历史日志就不需要了,通俗地讲叫“归档”,专业术语是Checkpoint。所以Redo Log其实是一个固定大小的文件,循环使用,写到尾部之后,回到头部覆写(实际Redo Log是一组文件,但这里就当成一个大文件,不影响对原理的理解)。之所以能覆写,因为一旦Page数据刷到磁盘上,日志数据就没有存在的必要了。
图6-8展示了Redo Log逻辑与物理结构的差异,LSN(Log Sequence Number)是逻辑上日志按照时间顺序从小到大的编号。在InnoDB中,LSN是一个64位的整数,取的是从数据库安装启动开始,到当前所写入的总的日志字节数。实际上LSN没有从0开始,而是从8192开始,这个是InnoDB源代码里面的一个常量LOG_START_LSN。因为事务有大有小,每个事务产生的日志数据量是不一样的,所以日志是变长记录,因此LSN是单调递增的,但肯定不是呈单调连续递增。

图6-8 Redo Log逻辑结构与物理结构的差异

物理上面,一个固定的文件大小,每512个字节一个Block,循环使用。显然,很容易通过LSN换算出所属的Block。反过来,给定Redo Log,也很容易算出第一条日志在什么位置。假设在Redo Log中,从头到尾所记录的LSN依次如下所示:
(200,289,378,478,30,46,58,69,129)
很显然,第1条日志是30,最后1条日志是478,30以前的已经被覆盖。

6.5.3 Physiological Logging
知道了Redo Log的整体结构,下面进一步来看每个Log Block里面Log的存储格式。这个问题很关键,是数据库事务实现的一个核心点。
(1)记法1。类似Binlog的statement格式,记原始的SQL语句,insert/delete/update。
(2) 记法2。类似Binlog的RAW格式,记录每张表的每条记录的修改前的值、修改后的值,类似(表,行,修改前的值,修改后的值)。
(3) 记法3。记录修改的每个Page的字节数据。由于每个Page有16KB,记录这16KB里哪些部分被修改了。一个Page如果被修改了多个地方,就会有多条物理日志,如下所示:
(Page ID,offset1,len1,改之前的值,改之后的值)
(Page ID,offset2,len2,改之前的值,改之后的值)
前两种记法都是逻辑记法;第三种是物理记法。Redo Log采用了哪种记法呢?它采用了逻辑和物理的综合体,就是先以Page为单位记录日志,每个Page里面再采取逻辑记法(记录Page里面的哪一行被修改了)。这种记法有个专业术语,叫PhysiologicalLogging。
要搞清楚为什么要采用PhysiologicalLogging,就得知道逻辑日志和物理日志的对应关系:
(1)一条逻辑日志可能产生多个Page的物理日志。比如往某个表中插入一条记录,逻辑上是一条日志,但物理上可能会操作两个以上的Page?为什么呢,因为一个表可能有多个索引,每个索引都是一颗B+树,插入一条记录,同时更新多个索引,自然可能修改多个Page。
如果Redo Log采用逻辑日志的记法,一条记录牵涉的多个Page写到一半系统宕机了,要恢复的时候很难知道到底哪个Page写成功了,哪个失败了。
(2)即使1条逻辑日志只对应一个Page,也可能要修改这个Page的多个地方。因为一个Page里面的记录是用链表串联的,所以如果在中间插入一条记录,不仅要插入数据,还要修改记录前后的链表指针。对应到Page就是多个位置要修改,会产生多条物理日志。
所以纯粹的逻辑日志宕机后不好恢复;物理日志又太大,一条逻辑日志就可能对应多条物理日志。Physiological Logging综合了两种记法的优点,先以Page为单位记录日志,在每个Page里面再采用逻辑记法。

6.5.4 I/O写入的原子性(Double Write)
要实现事务的原子性,先得考虑磁盘I/O的原子性。一个LogBlock是512个字节。假设调用操作系统的一次Write,往磁盘上写入一个Log Block(512个字节),如果写到一半机器宕机后再重启,请问写入成功的字节数是0,还是[0,512]之间的任意一个数值?
这个问题的答案并不唯一,可能与操作系统底层和磁盘的机制有关,如果底层实现了512个字节写入的原子性,上层就不需要做什么事情;否则,在上层就需要考虑这个问题。假设底层没有保证512个字节的原子性,可以通过在日志中加入checksum解决。通过checksum能判断出宕机之后重启,一个Log Block是否完整。如果不完整,就可以丢弃这个LogBlock,对日志来说,就是做截断操作。
除了日志写入有原子性问题,数据写入的原子性问题更大。一个Page有16KB,往磁盘上刷盘,如果刷到一半系统宕机再重启,请问这个Page是什么状态?在这种情况下,Page既不是一个脏的Page,也不是一个干净的Page,而是一个损坏的Page。既然已经有Redo Log了,不能用Redo Log恢复这个Page吗?
因为Redo Log也恢复不了。因为Redo Log是Physiological Logging,里面只是一个对Page的修改的逻辑记录,Redo Log记录了哪个地方修改了,但不知道哪个地方损坏了。另外,即使为这个Page加了checksum,也只能判断出Page损坏了,只能丢弃,但无法恢复数据。有两个解决办法:
(1)让硬件支持16KB写入的原子性。要么写入0个字节,要么16KB全部成功。
(2)Doublewrite。把16KB写入到一个临时的磁盘位置,写入成功后再拷贝到目标磁盘位置。
这样,即使目标磁盘位置的16KB因为宕机被损坏了,还可以用备份去恢复。

Redo Log的原理比较复杂,在接下来的1篇中,将接着这个话题继续探讨。

后记: 本文节选自作者书籍《软件架构设计:大型网站技术架构与业务架构融合之道》。
作者微信公众号:架构之道与术。公众号底部菜单有书友群可以加入,与作者和其他读者进行深入讨论。也可以在京东、天猫上购买纸质书籍。

原文地址:https://www.cnblogs.com/travis2046/p/10695972.html

时间: 2024-08-01 12:46:22

数据库原理 - 序列3 - 事务是如何实现的? - Redo Log解析的相关文章

数据库原理 - 序列4 - 事务是如何实现的? - Redo Log解析(续)

> 本文节选自<软件架构设计:大型网站技术架构与业务架构融合之道>第6.4章节. 作者微信公众号:> 架构之道与术.进入后,可以加入书友群,与作者和其他读者进行深入讨论.也可以在京东.天猫上购买纸质书. ## 6.5.5 Redo Log Block结构 Log Block还需要有Check sum的字段,另外还有一些头部字段.事务可大可小,可能一个Block存不下产生的日志数据,也可能一个Block能存下多个事务的数据.所以在Block里面,得有字段记录这种偏移量.图6-9展示了

[转]undo log与redo log原理分析

数据库通常借助日志来实现事务,常见的有undo log.redo log,undo/redo log都能保证事务特性,这里主要是原子性和持久性,即事务相关的操作,要么全做,要么不做,并且修改的数据能得到持久化. 假设数据库在操作时,按如下约定记录日志: 1. 事务开始时,记录START T 2. 事务修改时,记录(T,x,v),说明事务T操作对象x,x的值为v 3. 事务结束时,记录COMMIT T undo log原理 undo log是把所有没有COMMIT的事务回滚到事务开始前的状态,系统

InnoDB事务日志(redo log 和 undo log)详解

数据库通常借助日志来实现事务,常见的有undo log.redo log,undo/redo log都能保证事务特性,undolog实现事务原子性,redolog实现事务的持久性. 为了最大程度避免数据写入时io瓶颈带来的性能问题,MySQL采用了这样一种缓存机制:当query修改数据库内数据时,InnoDB先将该数据从磁盘读取到内存中,修改内存中的数据拷贝,并将该修改行为持久化到磁盘上的事务日志(先写redo log buffer,再定期批量写入),而不是每次都直接将修改过的数据记录到硬盘内,

MySQL的日志(二):事务日志(redo log和undo log)

本文目录:1.redo log 1.1 redo log和二进制日志的区别 1.2 redo log的基本概念 1.3 日志块(log block) 1.4 log group和redo log file 1.5 redo log的格式 1.6 日志刷盘的规则 1.7 数据页刷盘的规则及checkpoint 1.8 LSN超详细分析 1.9 InnoDB的恢复行为 1.10 和redo log相关的变量2.undo log 2.1 undo log的基本概念 2.2 undo log的存储方式

数据库原理-事务基本概念

2018-1-9 by Atlas 数据库访问 read(X):把数据X,从磁盘的数据库中读到内存的缓冲区中.write(X):把数据X,从内存的缓存区写回磁盘的数据库. ACID性质 1.原子性(Atomicity)一个事务对数据的所有操作,是一个不可分割的工作单元.这些操作要么全部执行,要么什么也不做(就对DB的效果而言).保证原子性是数据库系统本身的职责,由DBMS的事务管理子系统实现.2.一致性(Consistency)一个事务独立执行的结果,应保持数据库的一致性,即数据不会因事务的执行

JAVA-Unit01: 数据库原理 、 SQL(DDL、DML)

Unit01: 数据库原理 . SQL(DDL.DML) SQL语句是不区分大小写的,但是行业里习惯将关键字与分关键字用大小写岔开以提高可读性. SELECT SYSDATE FROM dual DDL语句 数据定义语言 用于操作数据库对象 数据库对象有:表,视图,索引,序列 创建表: CREATE TABLE employee( id NUMBER(4), name VARCHAR2(20), gender CHAR(1), birth DATE, salary NUMBER(6,2), jo

数据库原理相关知识

数据库原理相关知识 made by @杨领well([email protected]) 一.基础知识 1. 简述数据库系统的特点. 数据结构化 : 这是数据库系统与文件系统的本质区别. 数据的共享性高.冗余度低且易扩充 : 数据共享可以大大减少数据冗余, 节约存储空间.数据共享还能够避免数据之间的不相容性和不一致性. 数据的独立性高 : 数据独立性包括物理独立性和逻辑独立性. 数据由数据库管理系统统一管理和控制 : 数据的安全性保护(保护数据以防止不合法使用造成的数据泄密和破坏).数据的完整性

数据库原理分析(强烈推荐)

转自:https://blog.csdn.net/ptsx0607/article/details/68941750 一提到关系型数据库,我禁不住想:有些东西被忽视了.关系型数据库无处不在,而且种类繁多,从小巧实用的 SQLite 到强大的 Teradata .但很少有文章讲解数据库是如何工作的.你可以自己谷歌/百度一下『关系型数据库原理』,看看结果多么的稀少[译者注:百度为您找到相关结果约1,850,000个-] ,而且找到的那些文章都很短.现在如果你查找最近时髦的技术(大数据.NoSQL或J

《数据库原理》复习总结

<数据库原理>复习总结 数据库技术就是主要研究如何科学的组织和存储数据,高效的获取和处理数据,并可以满足用户各种不同的信息需求的技术,因为对数据库技术的需求非常大,所以学习这门课的知识和技术是非常必要的,应熟练弄清,掌握数据,数据管理,数据库,数据模型和概念模型的等专业术语的内涵. 第1章 绪论 1.掌握数据库.数据库管理系统.数据库系统(组成)的概念 2.了解数据库技术发展的三个阶段 3.掌握三级模式及二级映像的概念 4.理解数据库管理系统的主要功能 知识点: 数据:数据库系统研究和处理的对