MySQL 日志及数据备份恢复
MySQL 日志及数据备份恢复
MySQL三种日志详解
1、日志
日志是 MySQL
数据库的重要组成部分,记录数据库运行时期的各种状态信息。MySQL
日志主要包括错误日志、查询日志、 慢查询日志、事务日志、二进制日志几大类。作为开发,我们重点需要关注二进制日志(binlog
)和事务日志(redolog
和undolog
)
- 简单对比
日志 | 物理日志 | 逻辑日志 | 定义 | 作用 |
---|---|---|---|---|
redo log | InnoDB存储引擎层的日志 | N | 重做日志 | 事务的原子性和持久性 |
undo log | N | Y | 回滚日志 | 事务一致性,事务的回滚和实现mvcc |
binlog | N | MySQL Server层记录的日志 | 归档日志 | 主从数据同步,数据恢复 |
- 逻辑日志:可以简单理解为记录的就是sql语句 。
- 物理日志:
mysql
数据最终是保存在数据页中的,物理日志记录的就是数据页变更
2、redo log
redolog
包括两部分,一个是内存中的日志缓冲(redo log buffer
),另一种是磁盘上的日志文件(redo log file
)。MySQL
每次执行一条 DML 语句,现将记录写入到 redo log bufer
,然后再后续的某个合适的时间再一次性将多个操作记录写入到 redo log file
中。这种先写日志再写磁盘的技术就是 WAl(Write-Ahead Logging)
技术。
redo log
是 InnoDB 存储引擎层的日志文件,也叫做重做日志文件,用于记录事务操作的变化,记录的是数据修改后的值,不管事务是否提交都会被记录下来。在实例和介质失败时,redo log 文件就能排上用场,例如数据库断电,InnoDB 存储引擎会使用redo log
恢复到断电前的时刻,以此来保证数据的完整性。另外数据库也有了 crash-safe
能力。
redo log
的日志大小是固定的,记录满了以后需要从头循环重新写。比如可以配置一组4个文件,每个文件大小是 1GB,那么 redo log
中可以记录 4GB 的操作,InnoDB 会从第一个文件开始写入,直到第四个文件写满了,又回到第一个文件开头循环写,如下图。
write pos
是记录当前的位置,一边写一边往后移,写到第四个文件的末尾后就回到第一个文件开头。check point
是当前要擦除的位置,也是往后推移并且循环的,擦除记录之前要把记录更新到数据文件中。write pos
和 check point
之间的就是 redo log
上还空着的部分,也是可以用来记录新的操作的部分。如果 write pos
追上了 check point
,表示 redo log
满了,这个时候不能再执行新的更新,得停下来先擦掉一些记录,把 check point
往前推进一下。
- redo log 参数说明及刷盘机制
2、undolog
数据库事务四大特性中有一个是原子性,具体来说就是 原子性是指对数据库的一系列操作,要么全部成功,要么全部失败,不可能出现部分成功的情况。
实际上,原子性底层就是通过 undo log
来实现的。 undo log
主要记录了数据的逻辑变化,比如一条 insert
语句,对应一条 delete
的 undo log。对于每个 update
语句,对应一条相反的 update
的 undo log
,这样在发生错误的时候,就能回滚到事务之前的数据状态。
此外,保存了事务发生之前的数据的一个版本,还有另外的作用:
- 可以用于回滚
- 同时可以提供多版本并发控制下的读(MVCC),非锁定读
- 事务开始前,将当前事务版本生成
undo log
,undo log 也会生成redo log
来保证undo log
的可靠性 - 当事务提交以后,
undo log
并不能马上被删除,而是放入待清理的链表中,由purge 线程
判断是否还有其他事务在使用 undo 表的上一个事务之前的版本信息,从而决定是否可以清理undo log
的日志空间
4、binlog
binlog
二进制日志是 server 层的日志,无论 MySQL
使用什么类型的引擎,都会存在这种日志。日志的主要作用是主从复制和时间点恢复。另外需要注意,binglog
并不记录查询语句。
- 主从复制:在
master
端开启binlog
,然后将binlog
发送到各个slave
端,slave
端重放binlog
,从而达到主从数据一致 - 数据恢复:通过使用
mysqlbinlog
工具来恢复数据
binlog
是属于 MySQL Server
层面,又称为归档日志,属于逻辑日志,是以二进制的形式存在。记录的是操作语句的原始逻辑,仅仅依靠 binlog
是没有 crash-safe
能力的。binlog
不会想 redolog
那样擦掉之前的记录然后循环写,而是一直记录(超过有效期才会被清理),如果超过单日志的最大值(默认为 1G,可通过变量 max_binlog_size
设置),则会新起一个文件继续记录。但是由于日志可能是基于事务来记录的,而事务是绝对不可能也不应该跨文件记录,所以如果正好 binlog
日志达到最大值但是事务还没有提交则不会切换新的文件记录,而是继续增大日志。所以 max_binlog_size
指定的值和实际的 binlog
日志大小不一定相等。
binlog
可以用于主从复制,从库利用主库的 binlog
进行重播,实现主从同步。用于数据库的基于时间点,位点等的还原操作。binlog
的模式有三种:Statement,Row,Mixed
。在 MySQL5.7.7 之前,默认的格式是 Statement
,之后默认是 Row
。日志格式通过 binlog-format
指定。
数据恢复
- 恢复流程
- 读取 redolog 记录
- 从 check point开始,对日志进行重放
- 检查 redo log中那些事务是完整的并且处于 prepare 状态
- 根据 XID(事务 ID) 对照 binlog 的事务,并检查事务是否完整
- 事务完整,重新设置redo log 的 commit 标识
- 事务不完整则根据 XID 找到 undo log 进行事务回滚
下面我们根据事务提交流程,在不同的阶段时刻,看看MySQL突然奔溃后,按照上述流程是如何恢复数据的。
时刻A(刚在内存中更改完数据页,还没有开始写redo log的时候奔溃):
因为内存中的脏页还没刷盘,也没有写redo log和binlog,即这个事务还没有开始提交,所以奔溃恢复跟该事务没有关系;
时刻B(正在写redo log或者已经写完redo log并且落盘后,处于prepare状态,还没有开始写binlog的时候奔溃):
恢复后会判断redo log的事务是不是完整的,如果不是则根据undo log回滚;如果是完整的并且是prepare状态,则进一步判断对应的事务binlog是不是完整的,如果不完整则一样根据undo log进行回滚;
时刻C(正在写binlog或者已经写完binlog并且落盘了,还没有开始commit redo log的时候奔溃):
恢复后会跟时刻B一样,先检查redo log中是完整并且处于prepare状态的事务,然后判断对应的事务binlog是不是完整的,如果不完整则一样根据undo log回滚,完整则重新commit redo log;
时刻D(正在commit redo log或者事务已经提交完的时候,还没有反馈成功给客户端的时候奔溃):
恢复后跟时刻C基本一样,都会对照redo log和binlog的事务完整性,来确认是回滚还是重新提交。
总结
redo log
用来保证 crash-safe
,binlog
用来保证可以将数据库状态恢复到任一时刻,undo log
是用来保证事务需要回滚时数据状态的回滚和 MVCC
时,记录各版本数据信息。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!