MySQL事务日志和二进制日志(redo log、undo log、binlog)

1. innodb事务日志

innodb事务日志包括redo log和undo log。redo log是重做日志,提供前滚操作,undo log是回滚日志,提供回滚操作。

1.1 undo log

  • undo log不是redo log的逆向过程,其实它们都算是用来恢复的日志:
  • undo用来回滚行记录到某个版本。undo log一般是逻辑日志,根据每行记录进行记录。
  • innodb存储引擎对undo的管理采用段的方式。rollback segment称为回滚段,每个回滚段中有1024个undo log segment。

1.1.1 undo log的作用

undo log有两个作用:提供回滚和多个行版本控制(MVCC)。

在数据修改的时候,不仅记录了redo,还记录了相对应的undo,如果因为某些原因导致事务失败或回滚了,可以借助该undo进行回滚。

undo log和redo log记录物理日志不一样,它是逻辑日志。可以认为当delete一条记录时,undo log中会记录一条对应的insert记录,反之亦然,当update一条记录时,它记录一条对应相反的update记录。

当执行rollback时,就可以从undo log中的逻辑记录读取到相应的内容并进行回滚。有时候应用到行版本控制的时候,也是通过undo log来实现的:当读取的某一行被其他事务锁定时,它可以从undo log中分析出该行记录以前的数据是什么,从而提供该行版本信息,让用户实现非锁定一致性读取。

undo log是采用段(segment)的方式来记录的,每个undo操作在记录的时候占用一个undo log segment。

另外,undo log也会产生redo log,因为undo log也要实现持久性保护。

1.2 redo log

  • redo log是在物理格式上的日志,它记录的是数据库中每个页的修改,而不是某一行或某几行修改成怎样怎样,它用来恢复提交后的物理数据页(恢复数据页,且只能恢复到最后一次提交的位置)。
  • redo log是innodb层产生的,只记录该存储引擎中表的修改
  • redo log在数据准备修改前写入缓存中的redo log中,然后才对缓存中的数据执行修改操作;而且保证在发出事务提交指令时,先向缓存中的redo log写入日志,写入完成后才执行提交动作

1.3 事务两阶段提交过程

  • mysql通过WAL(write-ahead logging)技术保证事务
    • 在同一个事务中,每当数据库进行修改数据操作时,将修改结果更新到内存后,会在redo log添加一行记录记录“需要在哪个数据页上做什么修改”,并将该记录状态置为prepare
    • 等到commit提交事务后,会将此次事务中在redo log添加的记录的状态都置为commit状态,之后将修改落盘时,会将redo log中状态为commit的记录的修改都写入磁盘
      在这里插入图片描述
  • redo log记录方式:InnoDB 的 redo log 是固定大小的,比如可以配置为一组 4 个文件,每个文件的大小是1GB ,那么这块 日志模块总共就可以记录 4GB 的操作。写满了之后就要考虑擦除工作。
    • redolog的大小是固定的,在mysql中可以通过修改配置参数innodb_log_files_in_group和innodb_log_file_size配置日志文件数量和每个日志文件大小,
    • redolog采用循环写的方式记录,当写到结尾时,会回到开头循环写日志
    • write pos表示日志当前记录的位置,当ib_logfile_4写满后,会从ib_logfile_1从头开始记录;
    • check point表示将日志记录的修改写进磁盘,完成数据落盘,数据落盘后checkpoint会将日志上的相关记录擦除掉,即write pos->checkpoint之间的部分是redo log空着的部分,用于记录新的记录,
    • checkpoint->write pos之间是redo log待落盘的数据修改记录。
    • 当writepos追上checkpoint时,得先停下记录,先推动checkpoint向前移动,空出位置记录新的日志。
    • 有了redo log,当数据库发生宕机重启后,可通过redo log将未落盘的数据恢复,即保证已经提交的事务记录不会丢失。
      在这里插入图片描述

3 delete/update操作的内部机制

当事务提交的时候,innodb不会立即删除undo log,因为后续还可能会用到undo log,如隔离级别为repeatable read时,事务读取的都是开启事务时的最新提交行版本,只要该事务不结束,该行版本就不能删除,即undo log不能删除。

但是在事务提交的时候,会将该事务对应的undo log放入到删除列表中,未来通过purge来删除。并且提交事务时,还会判断undo log分配的页是否可以重用,如果可以重用,则会分配给后面来的事务,避免为每个独立的事务分配独立的undo log页而浪费存储空间和性能。

通过undo log记录delete和update操作的结果发现:(insert操作无需分析,就是插入行而已)

delete操作实际上不会直接删除,而是将delete对象打上delete flag,标记为删除,最终的删除操作是purge线程完成的。
update分为两种情况:update的列是否是主键列。
如果不是主键列,在undo log中直接反向记录是如何update的。即update是直接进行的。
如果是主键列,update分两部执行:先删除该行,再插入一行目标行。

4 binlog与redolog

  • redo log 是 InnoDB 引擎特有的; binlog 是 MySQL 的 Server 层实现的,所有引擎都可以使用,MySQL数据库中的任何存储引擎对于数据库的更改都会产生binlog。
  • redo log 是物理日志,记录的是 “ 在某个数据页上做了什么修改 ” ; binlog 是逻辑日志,记录的是这个语句的原始逻辑,比如 “ 给 ID=2 这一行的 c 字段加 1 ”。
    binlog 记录的都是事务操作内容,binlog 有三种模式:
    • Statement(基于 SQL 语句的复制)、
    • Row(基于行的复制) : row 格式的 binlog ,最后会有一个 XID event 。
    • Mixed(混合模式)。具体这三种模式的区别请看主从同步和主备同步专栏
  • redo log 是循环写的(类似一个循环队列),因为它的空间固定会用完; binlog 是可以追加写入的。 “ 追加写 ” 是指 binlog 文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。
  • redo在 事务执行过程中 会不断的写入,而 binlog 是在 事务最终提交前 写入的
    • binlog 仅在事务提交时记录,并且对于每一个事务,仅在事务提交时记录,并且对于每一个事务,仅包含对应事务的一个日志。
    • redolog 每个事务对应多个日志条目,并且事务的重做日志写入是并发的,并非在事务提交时写入,其在文件中记录的顺序并非是事务开始的顺序。
  • binlog可以作为恢复数据使用,主从复制搭建,redo log作为异常宕机或者介质故障后的数据恢复使用。

5 数据库crash后的恢复

在这里插入图片描述

  • 如果 redo log 里面的事务是完整的,也就是已经有了 commit 标识,则直接提交;
  • 如果 redo log 里面的事务只有完整的 prepare ,则判断对应的事务 binlog 是否存在并完整【redo log 和 binlog有一个共同的数据字段:XID】
    • 如果是,则提交事务 如果把 innodb_flush_log_at_trx_commit 设置成 1 ,那么 redo log 在 prepare 阶段就要持久化一次,因为这个崩溃恢复逻辑是要依赖于prepare 的 redo log ,再加上 binlog 来恢复的【对应时刻B,崩溃恢复过程中事务还是会被提交】
    • 否则,回滚事务。【对应时刻A, 由于此时 binlog 还没写, redo log 也还没提交,所以崩溃恢复的时候,这个事务会回滚。这时候, binlog 还没写,所以也不会传到备库】

6 相关参数

6.1 redo log相关参数

下面两项变量的设置保证了:每次提交事务都写入二进制日志和事务日志,并在提交时将它们刷新到磁盘中。

  • innodb_flush_log_at_trx_commit:设置为1,表示每次事务的redolog都直接持久化到磁盘(注意是这里指的是redolog日志本身落盘),保证mysql重启后数据不丢失。
  • innodb_flush_log_at_timeout
  • innodb_log_file_size:指定每个redo日志大小,默认值48MB
  • innodb_log_files_in_group:指定日志文件组中redo日志文件数量,默认为2
  • innodb_log_group_home_dir:指定日志文件组所在路劲,默认值./,指mysql的数据目录datadir

6.2 redo log相关参数

  • innodb_max_undo_log_size 1073741824 :控制undolog文件的大小,超过这个阈值,就会触发truncate undo logs,truncate后的undo log大小默认恢复为10MB,
    生产默认1G。
  • innodb_undo_directory ./
    undo文件的存储目录 (支持后期修改)
  • innodb_undo_log_truncate OFF
    5.7之后支持在线删除无用的undo logs,默认是关闭的。
  • innodb_undo_logs 128 (生产使用默认值)
    • 回滚段的数量默认是128个(最大),通过该参数可以将一个大的回滚段才分成多个小的回滚段,
    • 每个log segments最多存放128个事物。
    • 支持后期修改,但不可以超过 Innodb_available_undo_logs 参数
  • innodb_undo_tablespaces 4(生产配置)
    • undo log的数量,最少为2,
    • undo log的truncate操作有purge协调线程发起。
    • 在truncate某个undo log表空间的过程中,保证有一个可用的undo log可用。
    • 在mysql_install_db时初始化后不能被改动了,修改该值会导致MySQL无法启动。
    • 不支持后期修改。
  • innodb_purge_rseg_truncate_frequency 128(生产配置)
    • 5.7之后控制回放undo log的频率,默认128. 表示purge undo轮训128次之后,进行一次undo 的truncate操作,

6.3 binlog相关参数

  • sync_binlog: 表示没写缓冲N次就同步到磁盘,如果将N设为1,即sync_binlog表示采用同步写磁盘的方式来写二进制日志,在MySQL5.7.7后,默认为1。会对数据库的IO系统带来一定影响,但可以得到最大的高可用行
  • max_binlog_size:指定单个binlog文件最大值。默认值为1g,最大值1g,如果超过该值,则产生新的binlog文件,后缀名+1,并记录到.index文件。
  • binlog_cache_size:使用事务表存储引擎(如innodb存储引擎)时,所有未提交的binlog日志会被记录到一个缓存中去,等事务提交时再将缓存中的binlog写入到binlog文件中。缓存的大小由binlog_cache_size决定,默认大小为32K。
  • expire_logs_days:表示binlog文件自动删除N天前的文件。默认值为0,表示不自动删除,最大值99.要手动删除binlog文件,可以使用purge binary logs语句
  • binlog_rows_query_log_events:默认为不启用,启用binlog_rows_query_log_events时,会在binlog日志中记录原始SQL语句
  • binlog_checksum:该参数目的就是写入binlog进行校验,有两个值[crc32|none],默认为crc32
  • binlog-do-db:表示需要写入日志的数据库,默认为空,表示同步所有库
  • binlog-ignore-db:表示忽略写入日志的数据库,默认为空,表示同步所有库
  • log-slave-update:表示从master端取得并执行的binlog,写入自己的binlog文件中,一般应用在master=>slave=>slave架构
  • binlog_format:记录binlog的格式。[statement,row,mixed],在MySQL5.7.7之后,默认为row。

版权声明:本文为penriver原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。