目录
一、binlong
1、binlog介绍
作用
binlog是 mysql server 层的一种二进制日志,用来记录数据库的写入操作,并以"事务"的形式保存在磁盘上,主要的使用场景有主从复制和数据恢复。
特点
- 记录了对 MySQL 数据库执行了更改的所有操作,包括表结构变更(CREATE、ALTER、DROP TABLE…)、表数据修改(INSERT、UPDATE、DELETE...),但不包括 SELECT 和 SHOW 这类操作,因为这类操作对数据本身并没有修改;若更改操作并未导致数据库变化,那么该操作也会写入 binlog
- binlog是追加写,写到一定大小会切换到下一个,并不会覆盖以前的日志。
2、日志格式
- statement:只记录执行的 SQL,不需要记录每一行数据的变化,因此极大的减少了 binlog 的日志量,但是类似 set update_time=now() 这种情况,可能会导致主从数据不一致。
- row:记录SQL涉及到的每行数据的修改,由于要记录每一行数据的变化,因此缺点是会产生大量的日志,mysql 5.7.7之后默认 row 模式
- mixed:两种方案折中,MySQL会判断这条SQL语句是否会引起数据不一致,如果是,就用row模式,否则就用statement模式
3、写入流程
先把日志写到binlog cache,事务提交的时候,再根据刷盘规则将binlog cache写入文件。
默认情况:每次提交事务都会执行 write + fsync
write:将 mysql 缓存写到文件系统的 page cache,并没有把数据持久化到磁盘,速度比较快
fsync:文件系统的 page cache 持久化到磁盘
二、redo log
1、redo log作用
- redo log (重做日志)是InnoDB存储引擎产生的,记录事务对数据页的修改。奔溃恢复时,重启后InnoDB会使用redo log恢复数据,保证了数据的持久性。
- 每一次更新都需要写到磁盘上。然后磁盘也要找到对应的记录,然后再更新,整个过程IO成本、查找成本太大,为了解决这个问题,MySQL的设计者采用了WAL技术来解决。WAL全称是Write Ahead Logging,意思就是先写日志,再写磁盘。
2、刷盘时机
redo log 为了提高性能也使用了缓存redo log buffer ,可以通过 innodb_flush_log_at_trx_commit 来配置刷盘策略,默认 = 1 ,不会丢数据。除了事务提交时刷盘,InnoDB存储引擎还有一个后台线程,每隔1秒,执行一次 write + fsync 刷盘。
- 0 :每次事务提交时不进行刷盘操作,mysql挂了会丢失1秒数据
- 1 :每次事务提交时都将进行刷盘操作 write + fsync,不会丢数据
- 2 :每次事务提交时只执行write,mysql挂了不会丢数据,服务器挂了会丢失1秒数据
还有一种情况,当redo log buffer占用的空间即将达到 innodb_log_buffer_size 一半的时候,后台线程会主动刷盘
3、redo log如何写入
简介:redo log默认情况下存储在data目录下ib_logfile0 、ib_logfile1,可以通过 innodb_log_file_size 设置大小, innodb_log_files_in_group 设置文件个数,比如可以配置为一组4个文件,每个文件的大小是 1GB,整个redo log 日志文件组可以记录4G的内容,
redo log是循环写的:
- write pos:当前记录的位置,一边写一边后移
- checkpoint:当前要擦除的位置,也是往后推移并且循环的,脏页刷盘,checkponit往后移。擦除记录之前要把记录更新到数据文件中。
- 绿色的部分表示可以记录新的操作,是未刷入磁盘的日志。如果write pos追上了check point,表示redo log满了,这个时候就不能继续执行新的操作,需要停下擦除一些记录,并且把check point往后推进。
备注:每个数据页都有一个LSN,redo log 中也记录了LSN,当数据库异常重启时,系统读取redo log并定位到checkpoint位置,如果此时当redo log中的LSN大于数据页中的LSN,说明redo log中的数据未完全写入数据页中,那么将从数据页中记录的LSN开始,从redo log中恢复数据。比如redolog 的LSN 是 13000,数据库页的LSN是 10000,那么系统将会恢复redo log 中LSN从10000开始到13000的记录到数据页中。当redo log中的LSN小于数据页中的LSN时,说明数据页已经被刷到该位置,所以不需要进行恢复。
4、怎么提交数据进行刷盘
二阶段提交:通过二阶段提交保证奔溃恢复时不会有丢失事务数据或者主从不一致的问题
InnoDB事务提交之前并不是直接写redo log,而是使用了二阶段提交,将redo log的写出拆成了两个步骤:prepare 和 commit,这就是"两阶段提交"。
Prepare阶段(Execute阶段):InnoDB引擎把新数据更新到内存,同时把Insert操作记录到redo log并刷盘,此时redo log的状态为 prepare;
Commit阶段: Server执行器生成这个操作的Binlog,并落盘,执行器调用引擎的提交事务接口,引擎把刚刚写入的redo log状态更新为 commit状态.
为什么要使用两阶段提交呢?
假设没有redo log直接提交:
- 先写binlog,没写redolog。mysql崩溃,事务回滚,但是binlog已经写入,同步到从库,最终导致主从不一致。
- 先写redo log,没写binlog。mysql崩溃,重启,通过redo log恢复事务,但是binlog里并没有这个事务,主从不一致,如果通过binlog来恢复数据,也会丢失事务。
binlog能不能崩溃恢复?
不可以,因为binlog是追加写入的,只要开启了binlog,所有的更新记录都会被写入,保存的是全量的日志, InnoDB不能区分出哪些数据已经刷盘,哪些还没有。而redo log是循环写的,checkpoint 和 write pos 之间的 redo log都是未刷入磁盘的日志。
4、奔溃恢复流程
崩溃恢复流程
三、undolog
InnoDB事务修改数据之前会记录undo log并且持久化,undo log通过回滚事务指针形成了链表。
使用场景:
1、MVCC
2、通过rollback主动回滚事务
3、崩溃恢复未完成的事务通过undo log回滚
参考: