前言
Write-Ahead Log
(预先日志持久化):在持久化一个数据页之前,先将内存中相应的日志页持久化。
事务有四大特性: 原子性、一致性、隔离性和持久性。
- 事务的隔离性由 锁机制 实现。
-
而事务的原子性、一致性和持久性由事务的 redo 日志和undo 日志来保证。
REDO LOG
称为 重做日志 ,提供再写入操作,恢复提交事务修改的页操作,用来保证事务的持久性。- UNDO LOG 称为 回滚日志 ,回滚行记录到某个特定版本,用来保证事务的原子性、一致性。
有的DBA或许会认为 UNDO 是 REDO 的逆过程,其实不是。
- redo log是物理日志,记录的是数据页的物理变化,undo log不是redo log的逆过程
-
undo log是逻辑日志,对事务回滚时,只是将数据库逻辑地恢复到原来的样子。
-
redolog
:是存储引擎层(innodb
)生成的日志,记录的是”物理级别”上的页修改操作,比如页号xxx
、偏移量yyy
写入了'zzz”
数据。主要为了保证数据的可靠性; undo log
:是存储引擎层(innodb
)生成的日志,记录的是逻辑操作日志,比如对某一行数据进行了INSERT
语句操作,那么undolog
就记录一条与之相反的DELETE
操作。主要用于事务的回滚(undo log
记录的是每个修改操作的逆操作)和 一致性非锁定读(undo log
回滚行记录到某种特定的版本—MVCC
,即多版本并发控制)。
redo
日志
为什么需要redo
好处和特点
好处
-
redo日志降低了刷盘频率
-
redo日志占用的空间非常小
特点
-
redo日志是顺序写入磁盘的
-
事务执行过程中,redo log不断记录
redo log
组成
Redo log可以简单分为以下两个部分:
redo log buffer
: 保存在内存中 (重做日志的缓冲 )-
redo log file
: 保存在硬盘中 (重做日志文件)
redo log buffer
:参数设置:innodb_log_buffer_size:
redo log buffer 大小,默认 16M ,最大值是4096M,最小值为1M。
可以通过show variables like '%innodb_log_buffer_size%'
查看
redo
整体流程
- 第1步:先将原始数据从磁盘中读入内存中来,修改数据的内存拷贝
-
第2步:生成一条重做日志并写入redo log buffer,记录的是数据被修改后的值
-
第3步:当事务commit时,将redo log buffer中的内容刷新到 redo log file,对 redo log file采用追加写的方式
-
第4步:定期将内存中修改的数据刷新到磁盘中
redo
刷盘策略
redo log的写入并不是直接写入磁盘的,InnoDB引擎会在写redo log的时候先写redo log buffer,之后以 一定的频率 刷入到真正的redo log file 中。这里的一定频率怎么看待呢?这就是要说的刷盘策略。
redo log buffer刷盘到redo log file的过程并不是真正的刷到磁盘中去,只是刷入到 文件系统缓存(page cache
)中去(这是现代操作系统为了提高文件写入效率做的一个优化),真正的写入会交给系统自己来决定(比如page cache足够大了)。那么对于InnoDB来说就存在一个问题,如果交给系统来同
步,同样如果系统宕机,那么数据也丢失了(虽然整个系统宕机的概率还是比较小的)。
针对这种情况,InnoDB给出 innodb_flush_log_at_trx_commit 参数,该参数控制 commit提交事务
时,如何将 redo log buffer 中的日志刷新到 redo log file 中。它支持三种策略:
- 设置为0 :表示每次事务提交时不进行刷盘操作。(系统默认master thread每隔1s进行一次重做日志的同步)
-
设置为1 :表示每次事务提交时都将进行同步,刷盘操作( 默认值 )
-
设置为2 :表示每次事务提交时都只把 redo log buffer 内容写入 page cache,不进行同步。由os自己决定什么时候同步到磁盘文件。
三种刷盘策略
1. Innodb_flush_log_at_trx_commit=1
1. Innodb_flush_log_at_trx_commit=2
1. Innodb_flush_log_at_trx_commit=0
写入redo log buffer
过程
Mini-Transaction
一个事务可以包含若干条语句,每一条语句其实是由若干个 mtr 组成,每一个 mtr 又可以包含若干条redo日志,画个图表示它们的关系就是这样:
redo 日志写入log buffer
每个mtr都会产生一组redo日志,用示意图来描述一下这些mtr产生的日志情况
不同的事务可能是 并发 执行的,所以 T1 、 T2 之间的 mtr 可能是 交替执行 的。
redo log block
redo log file
相关参数设置
innodb_log_group_home_dir
:指定redo log
文件组所在的路径,默认值为 ./ ,表示在数据库的数据目录下。MySQL的默认数据目录(var/lib/mysql
)下默认有两个名为ib_logfile0
和ib_logfile1
的文件,log buffer
中的日志默认情况下就是刷新到这两个磁盘文件中。此redo日志文件位置还可以修改。-
innodb_log_files_in_group
:指明redo log file
的个数,命名方式如:ib_logfile0
,iblogfile1
…iblogfilen
。默认2个,最大100个。
mysql> show variables like 'innodb_log_files_in_group';
+---------------------------+-------+
| Variable_name | Value |
+---------------------------+-------+
| innodb_log_files_in_group | 2 |
+---------------------------+-------+
#ib_logfile0
#ib_logfile1
-
innodb_flush_log_at_trx_commit
:控制redo log
刷新到磁盘的策略,默认为1。 -
innodb_log_file_size
:单个redo log
文件设置大小,默认值为 48M 。最大值为512G,注意最大值指的是整个redo log
系列文件之和,即(innodb_log_files_in_group * innodb_log_file_size )
不能大于最大值512G。
mysql> show variables like 'innodb_log_file_size';
+----------------------+----------+
| Variable_name | Value |
+----------------------+----------+
| innodb_log_file_size | 50331648 |
+----------------------+----------+
根据业务修改其大小,以便容纳较大的事务。编辑my.cnf文件并重启数据库生效
[root@localhost ~]# vim /etc/my.cnf
innodb_log_file_size=200M
日志文件组
总共的redo
日志文件大小其实就是:innodb_log_file_size × innodb_log_files_in_group
。采用循环使用的方式向redo日志文件组里写数据的话,会导致后写入的redo日志覆盖掉前边写的redo
日志?当然!所以InnoDB
的设计者提出了checkpoint
的概念。
checkpoint
如果 write pos 追上 checkpoint ,表示日志文件组满了,这时候不能再写入新的 redo log记录,MySQL 得停下来,清空一些记录,把checkpoint
推进一下.
参考文献
文章部分内容引用自宋红康老师的Mysql高级课程,在此表示感谢,如有侵权,请联系站长进行删除
<声明>:
谁都不是生下来就会的,都不是三体人,知识也可以遗传,我们的东西都是学习到的,所以每个人的知识体系难免有老师的身影,先学习后模仿,才能学会,至于笔记,摘抄部分我感觉难免,学会了就是自己的!