持久性底层实现原理

举报
上善若水. 发表于 2022/11/30 13:59:01 2022/11/30
【摘要】 持久性底层实现原理一旦事务完成,无论发生什么系统错误,它的结果都不会受到影响,事务的结果被写到持久化存储器中。底层实现原理是:redo log机制去实现的,mysql 的数据是存放在这个磁盘上的,但是每次去读数据都需要通过这个磁盘io,效率就很低,使用 innodb 提供了一个缓存 buffer,这个 buffer 中包含了磁盘部分数据页的一个映射,作为访问数据库的一个缓冲,从数据库读取一个...

持久性底层实现原理
一旦事务完成,无论发生什么系统错误,它的结果都不会受到影响,事务的结果被写到持久化存储器中。

底层实现原理是:redo log机制去实现的,mysql 的数据是存放在这个磁盘上的,但是每次去读数据都需要通过这个磁盘io,效率就很低,使用 innodb 提供了一个缓存 buffer,这个 buffer 中包含了磁盘部分数据页的一个映射,作为访问数据库的一个缓冲,从数据库读取一个数据,就会先从这个 buffer 中获取,如果 buffer 中没有,就从这个磁盘中获取,读取完再放到这个 buffer 缓冲中,当数据库写入数据的时候,也会首先向这个 buffer 中写入数据,定期将 buffer 中的数据刷新到磁盘中,进行持久化的一个操作。如果 buffer 中的数据还没来得及同步到这个磁盘上,这个时候 MySQL 宕机了,buffer 里面的数据就会丢失,造成数据丢失的情况,持久性就无法保证了。使用 redolog 解决这个问题,当数据库的数据要进行新增或者是修改的时候,除了修改这个 buffer 中的数据,还会把这次的操作写入到这个 redolog 中,如果 msyql 宕机了,就可以通过 redolog 去恢复数据,redolog 是预写式日志,会先将所有的修改写入到日志里面,然后再更新到 buffer 里面,保证了这个数据不会丢失,保证了数据的持久性,redolog 属于记录修改的操作,主要为了提交或者恢复数据使用!

事务隔离性由之前讲述的锁来实现。redo log称为重做日志,用来保证事务的持久性。redo通常是物理日志,记录的是页的物理修改操作。重做日志用来实现事务的持久性,即事务ACID中的D。其由两部分组成:一是内存中的重做日志缓冲,是易丢失的;二是重做日志文件,是持久的。

MySQL中把对底层页面的一次原子访问的过程称之为一个Mini-Transaction(MTR),这里的原子操作,指的是要么全部成功,要么全部失败,不存在中间状态。
Mini-Transaction一般遵循三条原则:
1、the fix rules:修改一个数据页,需要获得这个数据页的x-latch;访问一个页是需要获得s-latch或者x-latch;持有该页的latch直到修改或者访问该页的操作完成才释放。(latch是一种轻量级的锁,它锁定的时间特别短,在innodb中,latch又可以分为mutex(互斥量)和rwlock(读写锁)2种,它的目的在于保证并发线程操作临界资源的正确性。)
2、WAL:持久化一个数据页之前,需要将内存中响应的日志页先持久化
3、force-log-at-commit:在事务提交的时候,其产生的所有MTR日志都要刷到持久化设备中,从而保证崩溃恢复的逻辑。

InnoDB是事务的存储引擎,通过Force Log at Commit机制实现事务的持久性。当事务提交时,必须先将该事务的所有日志写入到重做日志文件进行持久化,待事务的COMMIT操作完成才算完成。为了确保每次日志都写入重做日志文件,在每次将重做日志缓冲写入重做日志文件后,InnoDB存储引擎都需要调用一次fsync操作。

由于重做日志文件打开并没有使用O_DIRECT选项,因此重做日志缓冲先写入文件系统缓存。为了确保重做日志写入磁盘,必须进行一次fsync操作。由于fsync的效率取决于磁盘的性能,因此磁盘的性能决定了事务提交的性能,也就是数据库的性能。

隔离性实现原理(一致性非锁定读(MVCC的原理))
多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。
底层实现原理:
写-写操作:通过加锁,原理和 java 里面的锁机制是一样的。
写-读操作:MVCC多版本并发控制,对一行数据的读和写两个操作默认是不会通过加锁互斥来保证隔离性,避免了频繁加锁互斥。

一行数据被多个事务依次修改过后,在每个事务修改完后,Mysql会保留修改前的数据undo回滚日志,并且用两个隐藏字段trx_id和roll_pointer把这些undo日志串联起来形成一个历史记录版本链。

在可重复读隔离级别,事务开启的时候,执行任何查询sql会生成当前事务的一致性视图read-view,也就是第一次select生成一个版本,read-view视图在事务结束之前都不会变化。

如果是读已提交隔离级别,在每次执行查询sql时都会重新生成视图read-view,也就是每次select生成一个版本。

执行查询时,从对应版本链里的最新数据开始逐条跟read-view做比,会拿着当前事务的id和readview视图数组里面的已创建的最小事务id和已创建的最大事务id进行比较,这里面分为三种情况:
第一种,当前事务的id小于数组里面最小的id,说明这个版本是已提交的事务生成的,表示这个数据可见。
第二种,当前事务比已创建的最大事务id还要大,说明这个版本还没开启事务,表示不可见。
第三种,如果刚好在这个区间,被访问的事务id在最小事务id与最大事务id之间,又有二种情况:

第一种,这个版本是由还没提交的事务生成的,不可见,
第二种,表示这个版本是已经提交了的事务生成的,可见。
做比对,得到最终的快照结果,通过这种机制保证了隔离性。

对于删除的情况可以认为是update的特殊情况,会将版本链上最新的数据复制一份,然后将trx_id修改成删除操作的 trx_id,同时在该条记录的头信息(record header)里的(deleted_flag)标记位写上true,来表示当前记录已经被 删除,在查询时按照上面的规则查到对应的记录如果delete_flag标记位为true,意味着记录已被删除,则不返回数 据。

注意:begin/start transaction 命令并不是一个事务的起点,在执行到它们之后的第一个修改操作InnoDB表的语句, 事务才真正启动,才会向mysql申请事务id,mysql内部是严格按照事务的启动顺序来分配事务id的。

总结: MVCC机制的实现就是通过read-view机制与undo版本链比对机制,使得不同的事务会根据数据版本链对比规则读取同一条数据在版本链上的不同版本数据。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。