MySQL(十九)MySQL事务日志(一)RedoLog
事务的四种特性:原子性
、一致性
、持久性
和隔离性都是基于什么机制实现的?
-
事务的隔离性由
锁机制
实现 -
而事务的
原子性
、一致性
和持久性
则由事务的redo
和undo
日志来实现的-
redo log
是重做日志
,提供再写入操作,恢复提交事务修改的页的操作,保证了事务的持久性
一般情况下,事务中的操作都是先对内存中的数据页进行的操作,只有内存的数据刷回磁盘中才能叫做持久化,这时候redo log就是为了恢复因为宕机导致内存中修改但是没能刷回磁盘的情况
-
undo log
是回滚日志
,回滚行记录到某个特定的版本,用来保证事务的原子性
和一致性
-
undo不是redo的逆过程,两者都可以被视作恢复操作
(redo log
是恢复磁盘记录保证数据持久性,undo log
则是将操作恢复成之前的状态),但是:
redo log
是存储引擎层
生成的日志,记录的是物理级别
上的页修改操作,比如页号xxx,偏移量yyy写入了zzz数据。主要是为了保证数据的可靠性。undo log
也是存储引擎层
生成的日志,但是记录的是逻辑操作
的日志,比如对某一行数据进行了insert操作,则undo log就是与之相反的delete语句,即每个操作的逆操作。主要用于事务的回滚
和一致性非锁定读
(undo log 回滚到某种特定的版本--MVCC
,多版本并发控制
)
1 Redo Log概述
InnoDB存储引擎是以页
为单位来管理存储空间的。在真正访问页面之前,需要把磁盘上的页缓存到内存中的buffer Pool
中才可以访问。之后所有的变更(指事务commit后)必须先更新缓冲池中的数据,然后缓冲池中的脏页会以一定的频率刷入磁盘(Check Point机制
),这么做的目的是优化CPU和磁盘之间IO速度的鸿沟,保证整体的性能不会下降太多。
1.1 为什么需要redo日志
-
一方面,缓冲池可以帮助优化CPU和磁盘之间IO速度的鸿沟,
Check Point机制
可以保证所修改的页面都能刷回磁盘,然而由于Check Point机制
不是每次变更都会触发,而是master线程隔一段时间去处理。所以最坏的情况就是,事务刚提交完写完缓冲池就宕机了,Check Point机制
来不及刷盘操作。 -
另一方面,事务要求应该有
持久性
特性,即一个更新提交完成的事务,即使数据库发生崩溃,这个事务对数据库的更改也不能消失那么,能通过更新一次就刷一次盘的方式来保证一致性吗?显然是不能的:这种简单粗暴的方式存在两个问题:
①修改量和磁盘刷新量不成正比,由于存储引擎是以页为单位来管理存储空间的,因此哪怕每次只是修改了一个页的一条记录的一个字段,也会将整个数据页刷回磁盘
②随机IO速度慢:一个事务会包含很多SQL语句,因此会牵扯到修改很多页面,这些修改的页面可能并不相邻,这也就意味着将某个事务的
buffer pool
中的页面刷回磁盘的时候,需要进行很多的随机IO
-
因此redo日志的思路是:并不需要把所有修改的数据页全部刷回磁盘,只需要记录修改的地方即可。InnoDB引擎采用了
WAL(Write Ahead Logging)
技术,即先写日志再写磁盘,只有写入redo log
成功,才算事务提交成功,当发生数据库宕机且未刷新回磁盘的时候,就可以通过redo log
恢复。
![image-20230504201039092](https://hikaru0530.oss-cn-hangzhou.aliyuncs.com/PicGo/image-20230504201039092.png)
1.2 redo log的优点
- 降低了刷盘频率
- 占用空间小(只需要存储表空间id、页号、偏移量以及需要更新的值)
1.3 redo log的特点
- redo log是顺序写入磁盘的:在执行事务的过程中,每执行一条语句,就可能产生若干条redo日志,这些日志是按照产生的顺序写入磁盘的,也就是顺序IO效率要比随机IO快很多(这里的IO不是指的刷盘IO!!!而是写入内存的缓冲池和写入磁盘redo log的对比)
- 事务执行过程中redo log不断记录:redo log是
存储引擎层
产生的,bin log是数据库层
产生的,因此redo log 会在事务的操作执行期间不断写入日志,bin log则是事务执行完成之后一次性写入(用于主从复制)
1.4 redo log的组成
redo log 可以简单分为一下两个部分:
-
重做日志的缓存(redo log buffer)
:保存在内存中,是易失的。在mysql启动的时候,就向操作系统申请了一大片称为redo log buffer的连续内存
空间,这段内存空间被划分为了连续的redo log block
。一个redo log block
占512字节
的大小。参数设置:innodb_log_buffer_size,默认为15M
mysql> select @@innodb_log_buffer_size -> ; +--------------------------+ | @@innodb_log_buffer_size | +--------------------------+ | 16777216 | +--------------------------+ 1 row in set (0.00 sec)
-
重做日志文件(redo log file):保存在硬盘中,是持久的。如下面的
ib_logfile0
和ib_logfile1
,这两个文件大小是相等的,是因为这个空间是先开辟出来的,防止无线扩大。