【MySQL】日志简述

1,423 阅读4分钟
  • 本文是笔记类型文章,只有结论没有证明,可用于复习巩固知识,不能用于新知识的学习。如有错误,恳请指正,不胜感谢。
  • 转载请于文首标明出处:【MySQL】日志简述 - 掘金 (juejin.cn)
  • 文章仍未完工,内容会逐步完善

系列文章:

binlog

binlog 称为二进制日志(Binary Log),是 MySQL 服务层的日志,用于记录执行的写操作语句。只有事务提交后才会写 binlog,当事务提交但是数据没有落盘时如果发生宕机,则在重启之后可以通过 mysqlbinlog 和 binlog 重做事务。由于是 MySQL 服务层的日志,因此可以对所有存储引擎提供支持。

由于 MySQL 服务层不负责存储,因此落盘操作由存储引擎控制,因此服务层必须通过 binlog 来保证 DML 执行的持久性。

配置

  • 启用与关闭

    可以通过在配置文件中配置 log-bin=[log_file_name] 或者执行 SET SQL_LOG_BIN=1 来开启 binlog。删除 log-bin 配置项或执行 SET SQL_LOG_BIN=0 可以关闭 binlog。

  • 写入时机:binlog 的写入时机由 sync_binlog 控制。

    • sync_binlog=0,MySQL 不控制 binlog 的刷新,由操作系统自行在空闲时刷入磁盘。
    • sync_binlog=N,N 为正整数,表示每 N 次事务,MySQL 手动将 binlog 刷入磁盘。

因此 sync_binlog=1 可以带来最高的一致性,通常我们也是选择配置为 1。

创建

以下情况会重新创建一个 binlog 文件:

  1. MySQL 重启。
  2. 使用 flush log 命令。
  3. 文件大小超过 max_binlog_sizemax_binlog_size 默认为最大值 1G,最小值为 4k。但是当单次 DML 大小超过 1G 时,由于不会将单次操作拆分为多个文件存储,因此会出现 binlog 大小大于 max_binlog_size 的情况。

写入事件

binlog 的写入事件包括:

  • STATEMENT:基于 SQL 语句保存。
  • ROW:基于行保存。
  • MIX:混合模式,一般的语句使用 STATEMENT 格式保存。对于无法完成主从复制操作的语句,如有 date() 函数的语句,则采用 ROW 格式保存。

redo log

redo log 又称重做日志,是 InnoDB 存储引擎的日志,由于 InnoDB 支持事务,redo log 就是用于保证事务执行一致性的。redo log 仅记录事务对哪些数据页做了哪些修改,采用顺序写的方式,因此写入速度非常快,不会对性能造成太大影响。当事务执行提交之后,如果数据还未落盘数据库就宕机了,重启后 InnoDB 会自动根据 redo log 对丢失的事务进行重做。

为什么事务提交时不直接将数据落盘呢?是由于对于数据的修改很多时候都是随机的,而 InnoDB 默认页大小是 16K,因此如果一个修改涉及到多个页,此时需要进行多次随机 IO。修改完之后又需要刷入磁盘,又需要进行多次随机 IO,速度非常慢。因此对于事务的写操作通常都会将修改缓存到内存中,等待空闲时写入。

InnoDB 的 WAL(Write Ahead Log)技术的产物就是 redo log,对于写操作,永远都是日志先行,先写入 redo log 确保一致性之后,再对修改数据进行落盘

log buffer

Log Buffer 逻辑结构图 -- Zohar Yip

redo log 除了在磁盘上的文件实体之外,还在内存中有一块日志缓冲区 log buffer。如果每次进行修改都直接写磁盘的话,效率并不高,因此使用一个缓冲区先在内存中记录写操作,等到多次写操作发生,再一次写入磁盘。通过将随机写优化为顺序写,可以极大提高 redo log 的性能。redo log buffer 有三种落盘策略,由 innodb_flush_log_at_trx_commit 控制:

  • 0:按秒写,按秒刷。每秒调用 write() 写入 OS Buffer 并调用 flush() 刷入磁盘。
  • 1:实时写,实时刷。每次事务提交都调用 write() 写入 OS Buffer 并调用 flush() 刷入磁盘。
  • 2:实时写,延迟刷。每次事务提交都调用 write() 写入 OS Buffer,但每秒调用 flush() 刷入磁盘。

因此采用延迟写策略时系统运行速度最快,但是发生意外会有 1s 的数据丢失。根据使用场景选择即可。

redo log 落盘策略

writeflush 的概念是由于存在 OS Buffer,OS Buffer 是操作系统为了协调内存与磁盘的速度而提供的写缓冲区。因此我们单纯的 write() 并无法保证数据即刻落盘,因此 OS 提供 flush() 系统调用来触发立刻刷新缓冲。

循环写入

redo log 采用循环写入的模式,当前写入位置有一个 write_pos 指针,当前已落盘的数据日志结尾有一个 check_point 指针,也就是位于安全点之前日志可以被删除,位于安全点之后的数据不可被删除。当 write_pos 与 check_point 相遇时,redo log 空间不够,此时需要立刻将部分数据落盘,后移 check_point 以保证 redo log 的使用。

undolog

三者的比较