前面介绍了三种日志:error log、slow log、binlog,这三种都是 Server 层的。今天的 redo log 是 InnoDB引擎专有的日志文件。html
用个酒店掌柜记帐的例子说明 redo log的做用。mysql
酒店掌柜有一个粉板,专门用来记录客人的赊帐记录。若是赊帐的人很少,那么他能够把顾客名和帐目写在板上。但若是赊帐的人多了,粉板总会有记不下的时候,这个时候掌柜必定还有一个专门记录赊帐的帐本sql
若是有人要赊帐或者还帐的话,掌柜通常有两种作法:数据库
当生意火爆时,不停有人来要赊帐或者还帐(更新操做),若是掌柜仍是用第一种作法,因为记到帐本上须要查找记录(随机读)那就会出现大量的人(更新操做)在等待,会影响工做(阻塞)。缓存
第二种作法,先记在粉板上,空闲时再写回帐本。由于记粉板的速度是很快的,就能大量处理赊帐或者还帐,当掌柜(MySQL)没那么忙的时候,就把粉板上的内容记到帐本上。但若是粉板(redo log)写满了,那这时候掌柜(MySQL)就要停下工做,先去把粉板(redo log)的内容写回帐本(磁盘)。性能
两种作法的区别是:操作系统
所以MySQL采用第二种作法,当有一条记录须要更新的时候,InnoDB引擎就会先把记录写到redo log(粉板)里面,并更新内存,这个时候更新就算完成了。同时,InnoDB引擎会在适当的时候,将这个操做记录更新到磁盘里面,而这个更新每每是在系统比较空闲的时候作,这就像打烊之后掌柜作的事。线程
这就是WAL(Write-Ahead Logging),先写日志,再写磁盘。指针
与粉板相似,redo log 也是有固定大小的。好比能够配置为一组4个文件,每一个文件的大小是1GB,那么这块“粉板”总共就能够记录4GB的操做。从头开始写,写到末尾就又回到开头循环写,以下面这个图所示。日志
两个指针:
有了 redo log,InnoDB 能够保证即便数据库发生异常重启,以前提交的记录都不会丢失,这个能力称为 crash-safe。
下面以一条Update语句来介绍 binlog 是如何记录的。这里在 binlog 里也有介绍过。
mysql> update T set c=c+1 where ID=2;
上面的流程采用了两阶段提交,那为何要采用两阶段提交呢?是为了让 binlog 和 redo log 之间的逻辑一致。
咱们假设一下上面的 update 语句在执行的每一个时刻,MySQL 崩溃了,看一下两个日志间的逻辑是如何保持一致的。
这样就能保证 redo log 和 binlog 的逻辑一致性。
两阶段提交是跨系统维持数据逻辑一致性时经常使用的一个方案。
这里要介绍一下 redo log 里很是重要的一个参数:innodb_flush_log_at_trx_commit
。
innodb_flush_log_at_trx_commit=0
表示提交事务的时候,不当即把 redo log buffer 里的数据刷入磁盘文件的,而是依靠 InnoDB 的主线程每秒执行一次刷新到磁盘。此时可能你提交事务了,结果 mysql 宕机了,而后此时内存里的数据所有丢失。
innodb_flush_log_at_trx_commit=1
表示提交事务的时候,就必须把 redo log 从内存刷入到磁盘文件里去,只要事务提交成功,那么 redo log 就必然在磁盘里了。注意,由于操做系统的“延迟写”特性,此时的刷入只是写到了操做系统的缓冲区中,所以执行同步操做才能保证必定持久化到了硬盘中。
innodb_flush_log_at_trx_commit=2
表示提交事务的时候,把 redo 日志写入磁盘文件对应的 os cache 缓存里去,而不是直接进入磁盘文件,可能 1 秒后才会把 os cache 里的数据写入到磁盘文件里去。
经过如下命令查看当前 innodb_flush_log_at_trx_commit
的值是多少:
mysql> select @@innodb_flush_log_at_trx_commit; +----------------------------------+ | @@innodb_flush_log_at_trx_commit | +----------------------------------+ | 1 | +----------------------------------+ 1 row in set (0.00 sec)
在 /etc/mysql/my.cnf
文件里设置 innodb_flush_log_at_trx_commit
选项:
#/etc/mysql/my.cnf innodb_flush_log_at_trx_commit=1
修改后,重启 MySQL 服务便可。