IE盒子

搜索
查看: 101|回复: 0

mysql事务的持久性 redo日志 刷盘时机 丢弃时机

[复制链接]

4

主题

10

帖子

16

积分

新手上路

Rank: 1

积分
16
发表于 2023-3-3 16:12:16 | 显示全部楼层 |阅读模式
学习于《mysql是怎样运行的-从根上理解mysql》 只记重点,没记推断逻辑,书籍不错,建议观看。
在真正访问页面的时候,需要先把磁盘中的页加载到内存中的buffer pool中,之后才可以访问。
事务的持久性,提交事务之后即使系统崩溃,这个事务对数据库所做的更改也不能丢失。
innodb是以页为单位进行磁盘IO的
将某个事务修改的buffer pool中的页面刷新到磁盘时,需要进行很多随机IO。

所以,只需要把事务修改的内容记录一下就好。当系统崩溃,重启之后只要按照内容记录的步骤更新一下数据页即可,那就满足持久性了。这个记录事务修改内容的日志就叫做重做日志(即redo日志)  
相比于直接将事务修改过的内存页面刷新到磁盘中,redo日志的好处是:1.占用空间小 2.顺序写入磁盘,即顺序IO。

即写入redo日志成功才可以返回事务提交成功标识
日志格式:类型+表空间ID+页号+日志具体内容

隐藏主键row_id的例子:全局变量自增主键,256倍数时刷到MAX ROW ID当中,这里刷的过程就是事务写入,类型比如MLOG 8TYPE,表示在页面某个偏移量处写入8字节的redo日志类型。

索引中的B+树的单个页面内使用单向链表连接记录,平行页面之间使用双向链表连接,单个页面大小16kb。 磁盘到内存至少是16kb(mysql一个页面的大小),内存到CPU则是64字节(伪共享)  

数据页中的记录按照索引列从小到大的顺序组成一个单向链表,每插入一条记录还需要更新上一条记录的记录头信息中的next_record属性来维护这个单向链表。目的是说明插入一条数据是要做出更多数据修改的,而不是单纯单个地方的内存操作。
所以这类使用了新的redo日志类型在存储这类复合操作,比如MLOG COMP REC INSERT(对应type为38):标识在插入一条使用紧凑行格式的记录时,redo日志的类型。
从物理层面看,这类日志都指明了对哪个表空间的哪个页进行了数据修改;
从逻辑层面看,它需要调用一些事先准备好的函数,在执行完这些函数后才可以将页面恢复成系统崩溃前的样子。比如系统因崩溃而重启后,服务器会调用向某个页面插入一条记录的相关函数,而redo日志中的那些数据就可以当成调用这个函数所需的参数。在调用完该函数后,页面中的pagendirslots等的值也就都被恢复到了崩溃前的样子
悲观插入:页分裂,多个页面进行修改,产生多条redo日志。
插入一条记录的过程必须是原子的,以组的形式来记录redo日志。只有解析到MLOGMULTIRECEND的redo日志时,才认为解析到了一组完整的redo日志,才会进行恢复。即要么全部的日志都恢复,要么一条也不恢复
MTR:mini transaction 对底层页面进行一次原子访问的过程。如修改一次MAX ROW ID的值,B+树插入一条记录。 一个事务对应多个语句,一个语句对应多个MTR,一个MTR对应多个redo日志,即一组日志

通过MTR生成的redo日志放在512字节的block中。innodb为了解决磁盘速度过慢的问题而引入buffer pool,写入redo日志也不能直接写入到磁盘当中。所以有redo log buffer(redo日志缓冲区),划分成若干个redo log block。log buffer在5.7.22当中默认值为16MB。
当MTR结束的时候,再将过程中产生的一组redo日志全部复制到log buffer当中。
两个事务的MTR可能是交替执行的,即不同事务的MTR对应的redo日志可能是交替写入log buffer的。

redo日志刷盘时机:也就是从buffer pool刷新到磁盘当中的时机
1。log buffer 空间不足。
2。事务提交前。(持久性的真正体现)
3。后台有一个线程大约以每秒一次的频率刷盘。
4。正常关闭服务器
5。做checkpoint时。

LSN:log sequence number  记录当前总共已经写入的redo日志量。起始值为8704
每一组由MTR生成的redo日志都有一个唯一的lsn值与其对应;lsn值越小,说明redo日志产生得越早

flush to disk lsn:表示刷新到磁盘中的redo日志量的全局变量。 当有新的redo日志写入到log buffer时,lsn的值会增长,但flush to disk lsn不变,随后随着不断有log buffer中的日志被刷新到磁盘上,flush to disk lsn的值也跟着增长,如果和lsn相同,说明log buffer中的所有redo日志都已经刷新到磁盘中了。

checkpoint lsn:表示当前系统中可以被覆盖的redo日志总量是多少,初始值也是8704。比如页a被刷新到磁盘上了,mtr1生成的redo日志就可以被覆盖了,所以可以进行一个增加checkpoint lsn的操作,这个过程就称为执行一次checkpoint
这里就涉及到redo log什么时候丢弃了。因为redo日志文件组是有限的,所以需要循环利用。参考 [MySQL] update语句的redo log过程  这里的讲解


  也就是当redo log日志的内容,已经由内存刷入到磁盘当中(也就是刷脏),那么对应的redo log就是可以被删除了,也就是可以被覆盖重写。(书里一直强调刷脏和执行checkpoint不是一回事,checkpoint要修改redo日志文件的管理信息,我理解的是一个线程先刷脏,另一个线程再执行checkpoint)

崩溃恢复:需要从对应的lsn值为checkpoint lsn的redo日志开始恢复页面。

这里一直强调事物的持久性,也就是如何让已经提交的事务保持持久性。假设一个事务执行了一半,并且这些redo日志都已经刷新到了磁盘中,那么在下次开机重启时会根据这些redo日志把页面恢复过来,可是这就造成了一个事务处于只执行了一半的状态。 那么这就违背了事物的原子性了啊! 其实,这些只执行了一半的事务对页面所做的修改都会被撤销,这是由undo日志作用的。即撤销日志。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表