前言

MySQL日志, 主要用于记录数据库运行期间的各种状态信息. 常用的日志主要有:

  • 二进制日志: binlog

  • 事务日志: redoLog、undoLog

binlog

  • binlog用于记录数据库的写入性操作(增删改), 以..01010..的形式存储在磁盘中. 且无论是InnoDB还是MyISAM都会记录binlog日志.

  • binlog可以通过参数设置来定制每个日志文件的大小.

binlog是一种 "逻辑日志", 记录类似于SQL语句的数据. 对应的有物理日志, 比如某个数据页的变更记录.

binlog的应用

  • 主从复制: Master记录binlog并发送, 然后Slave用收到的binlog刷数据.

  • 数据恢复: 数据库发生异常的时候, 通过记录的binglog回复数据.

binlog写入文件时机

由于 "持久性" 的限制, 只有在事务提交的时候才会记录binlog, 在此之前, binlog记录的内容都存储在内存中.

同时, 具体的写入时机, 还可以通过参数进行设置, 分为:

  • 0: 不做特殊限制, 通常由MySQL的Server决定写入时机.

  • 1: 每次事务提交都写入binlog到磁盘, 胜在稳定, 但是频繁写入的大量I/O会影响性能.

  • N(一个正整数): 每N次提交都写入, 会丧失一定的一致性, 但是可以提升系统性能.

参数为 "1", 是 MYSQL 5.7.7 及后续版本的默认值.

binlog日志格式

binlog会根据参数的设置, 处理写入时, 是基于SQL还是基于数据库的行记录.

  • STATMENT: 基于SQL语句的复制, 每条增删改的SQL都会记录binlog.

    • 优点: 区别于基于行记录变更的日志, 只记录SQL的日志量较少, I/O较少.
    • 缺点: 如果执行了sleep(), 会导致主从数据同步不及时, 造成主从同步不一致.
  • ROW: 基于行记录变更的记录, 记录哪条数据被如何修改了.

    • 优点: 记录准确, 不关心过程.
    • 缺点: 日志量大, 在表字段变更的时候会记录全表的日志.
  • MIXED: 混合复制.

参数为 "ROW", 是 MYSQL 5.7.7 及后续版本的默认值.

redolog

redolog记录了事务对哪些数据页做了哪些修改.

redolog主要是防止在保证数据库的一致性时, 不必要的数据页同步造成的性能问题(比如: 为了保证每次事务提交的时候, 事务涉及的数据页都被持久化到磁盘上):

  1. InnoDB以页为单位进行磁盘交互, 如果一个事务只修改一个页里面的几个字节(upate ... status = 1) , 但是刷新的时候需要把这一整个数据页都刷进磁盘, 造成了不必要的I/O.

  2. 如果涉及批量操作的事务, 那么数据页很有可能在磁盘上没有连续存储, 这样磁盘还需要进行反复的扫描定位, 随机I/O的性能较差.

redolog的写入

redolog分为

  1. 日志缓冲(存储在内存中)

  2. 日志文件(存储在磁盘中)

两部分. 当MySQL进行数据库的增删改操作时, 优先将变动数据写入日志缓冲中, 后续再将累计的缓存数据写入日志文件中.

但是操作系统往往不能允许某一个用户的内存中的内容直接写入磁盘. 所以缓存中的数据首先要经过缓冲区, 再从缓冲区由系统调用对应的函数写入到磁盘中.

mysql_logwrite

具体, 日志缓存中的数据什么时候触发写入, 也可以通过参数进行配置:

  • 0: 事务提交的数据统一存入用户空间的日志缓存中, "每秒一次" 写入内核空间的缓冲区中, 并由操作系统写入磁盘, I/O 相对较优但是存在丢失1s数据的情况.

  • 1: 事务提交的所有数据都会直接进行 "日志缓存 -> 缓冲区 -> 写入磁盘" 的操作, 稳定, 但是I/O性能较差.

  • 2: 事务提交的数据会进行到 "日志缓存 -> 缓冲区", 再由缓冲区 "每秒一次" 写入磁盘, 和第一种情况相同.

redolog的恢复

redolog_work

innoDB启动的时候, 无论是否是故障恢复, 都会检查checkPoint的刷盘位置和实际刷盘位置是否相符.

redolog 和 binlog 的区别

redolog binlog
文件大小 大小固定不可修改 单个文件大小可以通过配置修改
载体 InnoDB独有 所有DB的Server都有
记录方式 循环记录, 写到结尾再从头开始写 追加记录, 单个文件超出限制开新的文件
使用场景 崩溃恢复 主从复制

undolog

一句话讲, undolog通过反向执行SQL的方式(执行了ADD的SQL, 就生成一条DELETE的备用)来实现数据库的原子性(同一个事务里的操作, 要么都成功要么都不成功).

一条语句的执行伴随着怎样的日志们变动?

update A SET B = 1 WHERE p_k = 2

  1. InnoDB尝试获取p_k为2的行记录. (如果p_k为2的行记录所在的数据页本来在内存中, 就直接返回给执行器; 否则, 需要先从磁盘读入内存, 然后再返回, 并将获取的数据存入内存).

  2. 执行器拿到InnoDB给的行记录, 进行赋值, 得到新的一行数据, 再调用引擎接口写入这行新数据.

  3. InnoDB将新的行记录写到内存中, 同时将这个更新操作记录到 redolog. 然后告知执行器执行完成了, 随时可以提交事务.

  4. 执行器生成这个操作的 binlog, 并把 binlog 写入磁盘.

  5. 执行器调用InnoDB的提交事务接口, InnoDB把刚刚写入的 redolog 改成提交(commit)状态, 更新完成.