04_binlog 日志
1256字约4分钟
2024-08-10
MySQL binlog 是什么
之前我们说的 redo log
是一种偏向物理性质的重做日志,记录的是类似这样的东西:“对哪个数据页中的什么记录,做了什么修改”
redo log
是属于 InnoDB
存储引擎特有的东西
binlog
叫做归档日志,是一种偏向逻辑性的日志,类似于“对 user
表中 id = 10
的一行数据做了更新操作,更新以后的值是什么”
binlog
不是 InnoDB
存储引擎特有的日志文件,是属于 MySQL Server
的日志文件
提交事务的时候,同时会写入 binlog
前面我们讲到,在提交事务的时候会把 redo log
日志写到磁盘文件,其实在提交事务的时候,还会把这次更新对应的 binlog
日志写到磁盘文件,如下图所示
上图增加了执行器这个组件,他负责与 InnoDB
存储引擎进行交互,包括从磁盘加载数据到 Buffer poll
中进行缓存、写入 undo
日志、更新 Buffer Pool
里的数据、写入 redo log buffer
、redo log
刷入磁盘、写 binlog
等等
执行器是非常核心的一个组件,负责和存储引擎配合完成一个 SQL
语句在磁盘与内存层面的全部数据更新操作
上图中把一次更新语句的执行拆分成了两个阶段,1、2、3、4
步骤属于执行更新语句阶段,5、6
属于提交事务阶段
binlog日志刷盘策略分析
对于 binlog
日志也有不同的刷盘策略,sync_binlog
参数控制 binlog
的刷盘策略,默认值是 0
sync_binlog
参数值为 0
时,binlog
日志写入磁盘的时候不是直接进入磁盘文件,而是进入 os cache
内存缓存,与之前分析一样,如果此时机器宕机,那么在 os cache
里的 binlog
日志是会丢失的,如下图
sync_binlog
参数值为 1
时,会强制在提交事务的时候,将 binlog
直接写入到磁盘文件里去,这样在提交事务之后,哪怕是机器宕机,磁盘上的 binlog
日志也不会丢失
基于 binlog 和 redo log 完成事务的提交
当我们把 binlog
写入磁盘文件之后,接着就会完成最终的事务提交
此时会把本次更新的 binlog
文件名称和 binlog
日志在文件里的位置,都写入到 redo log
日志文件,同时在 redo log
日志文件里写入一个 commit
标记
完成这些操作之后才算最终完成了事务的提交,如下图
最后在 redo log
中写入 commit
标记有什么意义呢?
commit
标记的作用是用来保持 redo log
日志与 binlog
日志一致的
假设在提交事务的时候有上图中 5、6、7
三个步骤,这三个步骤都执行完了才算是提交了事务,在刚完成步骤 5
的时候,mysql
宕机了,此时会怎么样?
由于 redo
日志里没有 commit
标记,此次事务可以判定为不成功,不会造成 redo
日志有此次更新日志,binlog
日志没有这次更新日志,出现数据不一致的情况
完成步骤 6
,也就是 binlog
写入磁盘了,此时 mysql
宕机也是同理,redo log
中没有最终的 commit
标记,此次事务提交是失败的
总之就是 redo log
中写入最终的事务 commit
标记了,事务才算是提交成功,此时 redo log
、binglog
里都有本次更新对应的日志,是完全一致的
后台 IO 线程随机将内存更新后的脏数据刷回磁盘
假设我们现在已经提交事务了,此次更新已经把内存 buffer pool
中的缓存数据更新了,但是磁盘上的数据还是旧值
所以 MySQL
有一个后台 IO
线程,会在之后的某个时间里,随机的把内存 buffer pool
中修改后的脏数据给刷回到磁盘上的数据文件中
当 IO
线程把 buffer pool
里修改后的脏数据刷回到磁盘之后,磁盘上的数据才会跟内存里一样
在 IO
线程把脏数据刷回磁盘前,哪怕 MySQL
宕机也没关系,因为重启之后会根据 redo
日志恢复之前提交事务做过的修改到内存里去
等到适当时机,IO
线程会把这个修改后的数据刷到磁盘文件里去