Contents

数据库-mysql-小林coding-日志篇

本系列笔记为作者在跟随小林coding学习的时候做的笔记。感谢小林大大。

  • undo log(回滚日志):Innodb 存储引擎层生成的日志,原子性,用于事务回滚和 MVCC。
  • redo log(重做日志):是 Innodb 存储引擎层生成的日志,持久性,用于故障恢复;
  • binlog (归档日志):Server 层生成的日志,用于数据备份和主从复制;

undo log

MySQL 会为没有begin和commit的单个语句隐式开启事务

  • 插入一条记录,存记录的主键值,回滚时删掉这个主键值
  • 删除一条记录,存这条记录的所有内容,回滚时插入到表中
  • 更新一条记录,存被更新的列的旧值,回滚时更新为旧值

每条undo日志都有 roll_pointer 指针和trx_id 事务id

  • trx_id 存修改操作的事务
  • roll_pointer 指针指向被修改的记录。该指针形成的链表就叫版本链

undo log 两大作用:

  • 实现事务回滚,保障事务的原子性
  • 实现 MVCC(多版本并发控制)关键因素之一

Buffer Pool

  • 读取数据需要先从磁盘读取到buffer pool,再从buffer pool读取
  • 修改数据时,仅修改buffer pool,并将响应的页设置为脏页,最后在合适的时候将脏页刷新到磁盘,这也叫做WAL (Write-Ahead Logging)技术

redo log

对 XXX 表空间中的 YYY 数据页 ZZZ 偏移量的地方做了AAA 更新时就会产生redolog日志,先写脏页再写redolog

redo log 和 undo log 区别:

  • redo log 记录事务「完成后」的数据状态,更新之后的值
  • undo log 记录事务「开始前」的数据状态,更新之前的值

redo log作用:

  • 实现事务的持久性,让 MySQL 有 crash-safe 的能力
  • 将写操作从「随机写」变成了「顺序写」,提升 MySQL 写入磁盘的性能

redo log 不是直接写入磁盘而是写入 redo log buffer,在后续持久化到磁盘

刷盘时机:

  • MySQL 正常关闭
  • redo log buffer空闲空间少于一半
  • InnoDB 的后台线程每隔 1 秒
  • innodb_flush_log_at_trx_commit参数控制每次事务提交时的操作,0不主动触发,1持久化到磁盘,2持久化到page cache(操作系统的页缓存)

redo log 文件写满了怎么办

重做日志文件组(redo log Group)由有 2 个 redo log 文件组成,ib_logfile0 和 ib_logfile1 。两个文件循环写。满了就阻塞mysql将脏页写入磁盘,同时清理可以擦除的redolog

binlog

binlog由服务层生成(可以供其他存储引擎使用),redolog和undolog由innodb存储层生成

一条更新操作后生成一条 binlog,事务提交时将该事务执行过程中产生的所有 binlog 写入 binlog 文件。

binlog 文件只记录所有数据库表结构变更和表数据的修改

主从复制依赖于 binlog。复制的过程是将 binlog 中的数据从主库传输到从库上。该过程默认不需要阻塞主库执行事务(异步)

主从复制过程:主库写 Binlog=》从库同步 Binlog=》从库回放 Binlog

一个主库一般跟 2~3 个从库(1 套数据库,1 主 2 从 1 备主)

主从复制模型:

  • 同步复制:阻塞直到所有从库成功响应,性能太差
  • 异步复制(默认模型):不阻塞
  • 半同步复制:阻塞直到某一个从库成功响应

binlog日志写到 binlog cache(Server 层的 cache),事务提交的时候再写到 binlog 文件中。一个事务的 binlog 是不能被拆开的

sync_binlog 控制binlog 每次提交事务时的操作

  • 0:只write,不fsync
  • 1:write后立刻fsync
  • N:write,然后提交N个事务后fsync

两阶段提交

MySQL 为了避免出现redo log 和 binlog 之间的逻辑不一致的问题,使用了「两阶段提交」来解决

两阶段提交都会存储XID

异常重启通过检查binlog中有没有XID来判断异常时机。如果有则是时刻A,需要进行事务回滚;如果没有则是时刻B,直接将redolog状态修改为commit即可。

 |