MySQL 日志
redo log
背景
Buffer Pool:在真正访问页面之前,需要将磁盘中的页面加载到内存的 Buffer Pool 中,之后才可以访问;
如果在内存中更新了,此时宕机了,在磁盘中没有更新数据,造成数据的丢失,违反了持久性
如果在事务提交之前,把数据更新到磁盘上,会存在两个问题:
- 刷新一个完整的页太浪费了,有时我们仅仅是改变了某一个页上的某个字节;
- 随机 I/O 刷新起来很慢,因为一个 SQL 语句可能会修改了多个页面,这些页面可能不相邻;
作用
记录事务对数据库的修改操作,比如增加,删除,更新等;在事物提交时,只需要把 redo log 持久化到硬盘即可,而不用等待到将缓存 Buffer Pool 中的数据持久化到硬盘中。
一旦发生数据库宕机,可以根据 redo log 中的日志信息恢复数据
- redo log 日志占用的空间非常小;
- redo log 日志是顺序写入磁盘的;
redo log 也有自己的缓冲区 redo log buffer
redo log 刷盘时机
刷盘即把 redo log buffer 中的数据刷新到 磁盘中去
- MySQL 正常关闭时;
redo log buffer空间不足时;- 事务提交时;
- 后台线程,以固定的频率把 buffer 中的日志刷新到磁盘;
- 做
checkpoint时; - 将
Buffer Pool中的脏页刷新到磁盘前;
undo log
回滚日志
在一个事务中,每当对一条记录进行改动时,都要留一手 —— 把回滚时所需要的东西记录下来
- 当插入一条语句 时,我们至少需要把该记录的 主键 记录下来,这样回滚时删除该主键对应的记录即可;
- 当删除一条语句时,我们需要把原来语句的内容记录下来,便于之后恢复;
- 当更新一条语句时,我们需要把旧值记录下来,便于回滚后恢复该值;
我们把这些为了回滚而记录的日志称为 撤销日志,执行该撤销日志,可以恢复到事务开启之前的状态;
基于 undo log 版本链
隐藏列
row_id:隐藏的主键,当没有定义主键,且没有不允许为 NULL 的 UNIQUE 的字段,就会把该隐藏列当作为主键;
trx_id:一个事务对某条聚簇索引记录进行改动时,都会把当前事务的事务 id 赋值给 trx_id 隐藏列;
roll_pointer:每次对某条聚簇索引记录进行改动时,都会把旧的版本写入 undo 日志中,这个隐藏列就相当于一个指针,可以通过它找到该记录修改前的信息;
版本链
每对记录进行一次改动,都会产生一个 undo 日志,每条 undo 日志都有一个 roll_pointer 属性,通过这个属性可以将这些 undo 日志串成一个链表。
版本链的头节点就是当前节点的最新值,我们之后利用这个记录的版本链来控制并发事务访问相同事务的行为,这种机制称为 多版本并发控制(Multi-Version-Concurrency Control,MVCC)
bin log
前面介绍的 redo log 和 undo log 是由 InnoDB 存储引擎生成的,而 binlog 是由 Server 层生成的
MySQL 在完成一条更新操作后,Server 层还会生成一条 binlog,等之后事务提交的时候,会将该事物执行过程中产生的所有 binlog 统一写 入 binlog 文件。
MySQL 的 binlog 主要记录三种事件:
- 对数据库 数据 的更新操作:
update、insert、delete - 对数据库 结构 的更新操作:
alter table、drop table、drop database、create index等 - 其他与数据库相关的事件,如授权操作、登录操作等
当数据库数据或者数据表结构发生改变后,binlog 会记录这些操作,用于 数据的恢复 和 主从复制
redo log 和 bin log 的不同
- 写入方式不同:
- redo log 是循环写,记录的是未写入磁盘的数据,而写入了磁盘的 redo log 会被删除掉;
- bin log 是追加写,会把任何数据的更改都记录在 bin log 中,保存着全量的日志;
- 适用对象不同
- redo log 是 InnoDB 中的 日志文件,只有该存储引擎才能使用;
- bin log 是 Server 层的日志文件,所有存储引擎都可以使用;
- 作用不同
- redo log 是用于维护事务的持久性;
- bin log 是用于恢复数据 和 主从复制;
基于 bin log 实现主从复制
MySQL 的主从复制依赖于 bin log,对于数据库中数据和数据库表结构的改变,都会记录到 bin log 日志中,通过把 bin log 中内容通过网络传输到从库中,完成数据的同步
主从复制的过程
- 写入 bin log:主库将更新的数据通过 log dump 线程写入 bin log 中,并把 bin log 文件发送给从库;
- 读取 bin log:从库通过 I/O 线程读取 bin log,写入到自己的 relay log 中,并返回响应;
- 重放 relay log:从库通过 SQL 线程重放 relay log,把主库更新的数据同步到从库中;