Binlog (二进制日志)
bin Log 作用
用于记录所有修改数据库数据的 SQL 语句或行级别的变化,主要用于主从复制和数据恢复。
binlog格式
-
STATEMENT模式:binlog里面记录的就是SQL语句的原文。优点是并不需要记录每一行的数据变化,减少了binlog日志量,节约IO,提高性能。缺点是在某些情况下会导致master-slave中的数据不一致
-
ROW模式:不记录每条SQL语句的上下文信息,仅需记录哪条数据被修改了,修改成什么样了,解决了STATEMENT模式下出现master-slave中的数据不一致。缺点是会产生大量的日志,尤其是alter table的时候会让日志暴涨
-
MIXED模式:以上两种模式的混合使用,一般的复制使用STATEMENT模式保存binlog,对于STATEMENT模式无法复制的操作使用ROW模式保存binlog,MySQL会根据执行的SQL语句选择日志保存方式
示例 1:使用不确定函数
某些情况下,使用不确定函数(如 UUID()、NOW() 等)会导致 STATEMENT 模式无法复制,因为每次执行时返回的结果可能不同。此时,ROW 模式可以准确记录每行数据的变化。
INSERT INTO my_table (id, value) VALUES (UUID(), NOW());
在 STATEMENT 模式下,这条语句可能在主库和从库中插入不同的 UUID 和 NOW 值。而在 ROW 模式下,每行数据的具体值会被记录并复制到从库。
示例 2:复杂事务
复杂事务中可能包含多个步骤,每一步骤都会影响数据的一致性。在这种情况下,使用 ROW 模式可以确保每个步骤的结果都被准确记录和复制。
BEGIN;
UPDATE my_table SET value = value + 1 WHERE id = 1;
DELETE FROM my_table WHERE id = 2;
INSERT INTO my_table (id, value) VALUES (3, 'test');
COMMIT;
在 STATEMENT 模式下,每个语句会被记录并在从库执行,但如果有依赖顺序或其他条件的语句,可能导致复制不一致。而在 ROW 模式下,每行数据的变化都会被准确记录。
bin Log记录顺序
- 在事务提交之前,MySQL 会将事务的所有修改记录到 binlog cache(binlog 缓冲区)。
- 当事务提交时,MySQL 会将 binlog cache 中的内容写入磁盘上的 binlog 文件。
- MySQL 保证 binlog 写入后,事务才会真正提交。
Redo Log(重做日志)
MySQL里常说的WAL技术,全称是Write Ahead Log,即当事务提交时,先写redo log,再修改页。
也就是说,当有一条记录需要更新的时候,InnoDB会先把记录写到redo log里面,并更新Buffer Pool的page,这个时候更新操作就算完成了
Buffer Pool是物理页的缓存,对InnoDB的任何修改操作都会首先在Buffer Pool的page上进行,然后这样的页将被标记为脏页并被放到专门的Flush List上,后续将由专门的刷脏线程阶段性的将这些页面写入磁盘。
Redo Log 作用
用于保证事务的持久性(即使数据库崩溃后,也能恢复到最新的提交状态)。
Redo Log 结构
InnoDB的redo log是固定大小的,比如可以配置为一组4个文件,每个文件的大小是1GB,循环使用,从头开始写,写到末尾就又回到开头循环写(顺序写,节省了随机写磁盘的IO消耗)
Write Pos是当前记录的位置,一边写一边后移,写到第3号文件末尾后就回到0号文件开头。
Check Point是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据文件
Write Pos和Check Point之间空着的部分,可以用来记录新的操作。如果Write Pos追上Check Point,这时候不能再执行新的更新,需要停下来擦掉一些记录,把Check Point推进一下
当数据库发生宕机时,数据库不需要重做所有的日志,因为Check Point之前的页都已经刷新回磁盘,只需对Check Point后的redo log进行恢复,从而缩短了恢复的时间
当缓冲池不够用时,根据LRU算法会溢出最近最少使用的页,若此页为脏页,那么需要强制执行Check Point,将脏页刷新回磁盘。
Redo log buffer刷盘
InnoDB首先将redo log放入到redo log buffer,然后按一定频率将其刷新到redo log file
下列三种情况下会将redo log buffer刷新到redo log file:
-
Master Thread每一秒将redo log buffer刷新到redo log file
-
每个事务提交时会将redo log buffer刷新到redo log file
-
当redo log缓冲池剩余空间小于1/2时,会将redo log buffer刷新到redo log file
Redo Log 记录顺序
- 当事务开始时,MySQL 会将对数据的修改先写入内存中的缓冲区。
- 在事务进行过程中,对数据的修改会先写入 redo log buffer(重做日志缓冲区)。
- 当事务提交时,MySQL 会将 redo log buffer 中的数据刷新(fsync)到磁盘上的 redo log 文件。
- 一旦 redo log 写入成功,事务才算真正提交。
Undo Log (回滚日志)
Undo Log 作用
用于支持事务的回滚操作,保证数据的一致性和隔离性。
Undo Log记录顺序
- 当一个事务对数据进行修改前,会先记录一份旧的数据快照到 undo log。
- 如果事务需要回滚,MySQL 会使用 undo log 将数据恢复到修改前的状态。
- undo log 在事务提交后,会被标记为可删除状态,并在后台逐步清理。
Binlog 、Undolog 、Redolog整体执行顺序
在一个事务的生命周期内,这些日志的记录顺序通常如下:
开始事务
对数据进行修改:
- 写入 undo log。
- 写入 redo log buffer。
- 写入 binlog cache。
事务提交:
- 刷新 redo log buffer 到磁盘。
- 写入 binlog cache 到 binlog 文件。
- 事务提交完成,数据对外可见。
Mysql 异常恢复机制
Undo Log
作用:Undo log 用于回滚未提交的事务,并支持多版本并发控制(MVCC)。
恢复:当 MySQL 重启时,会使用 undo log 回滚所有未提交的事务,以确保数据库处于一致的状态。
- MySQL 会扫描 undo log,找到所有未提交的事务,并逐一回滚这些事务的操作。
Redo Log
作用:Redo log 记录已提交事务的修改,用于崩溃恢复。
恢复:当 MySQL 重启时,会使用 redo log 重做所有已提交但尚未刷入数据文件的事务。
- MySQL 会扫描 redo log,将所有已提交的事务重新应用到数据文件中,确保数据持久化。
Binlog
作用:Binlog 用于记录所有修改数据的 SQL 语句或行级别的变化,主要用于主从复制和数据恢复。
恢复:在 MySQL 异常后,binlog 保证事务提交的持久性。
- 事务在提交之前,binlog cache 的内容会刷新到 binlog 文件。
- 如果 MySQL 在事务提交前崩溃,binlog 中不会有该事务的记录,确保了数据的一致性。
综上
Undo Log:在修改数据前记录旧数据快照,支持事务回滚,保证数据一致性和隔离性。
Redo Log:事务修改的数据先写入 redo log buffer,事务提交时刷新到磁盘,保证事务持久性。
Binlog:在事务提交之前记录所有修改到 binlog cache,事务提交时写入 binlog 文件,支持主从复制和数据恢复。
通过这种日志记录机制,MySQL 能够在发生故障时恢复数据,并保证数据的一致性和持久性。