mysql使用WAL机制,在执行更新操作时并不会直接写盘,而是先记redo log。
redo log格式
(本篇图片全部来自掘金小册中《MySQL是怎样运行的》一书)
type:innodb有很多类型的redo log格式,比如指定不同的偏移量等等;
data:日志详细内容;
mini-transaction
一条sql更新语句,其实需要会涉及很多页面更新逻辑,比如更新聚簇索引,更新二级索引等,在更新索引的时候,可能需要分裂节点,新申请页面等等。innodb规定,这些一个基础的操作必须是原子的,比如更新索引需要更新page页内的目录项信息,header信息以及数据行信息,那这些更新必须是原子的,不能只执行一部分。所以,redo log必须以组的形式提交,也叫作mini-transaction。
那么怎么识别一组redo log呢?
innodb规定一组redo log后会是一条特殊类型的redo log,专门用来做为结尾标记。
所以,事务和redo log的关系是这样的:
(本篇图片全部来自掘金小册中《MySQL是怎样运行的》一书)
redo log block
redo log使用一种大小为512字节的特殊类型的页存放redo log,这种页也叫作block。
(本篇图片全部来自掘金小册中《MySQL是怎样运行的》一书)
redo log buffer
类似于buffer pool,redo log也是用了缓存,叫做redo log buffer。内存中会开辟若干个block来存放redo log缓存。redo log写入是按照mini-transaction分组的,内存中有一个buffer_free变量,指向buffer中下一个可写入位置。
(本篇图片全部来自掘金小册中《MySQL是怎样运行的》一书)
LSN
log sequence number,redo log日志序号,递增,初始值是8704,每写入一条日志,就将LSN值增加日志长度,这个长度的计算会考虑header和trailer。
flushed_to_disk_lsn
记录已经被刷到磁盘的redo log buffer位置。
redo log刷盘时机:
1.redo log满了;
2.后台线程;
3.事务提交,当然这个并不是绝对的,取决于数据库innodb_flush_log_at_trx_commit配置。
4.buffer pool满了,需要刷脏页时;
5.checkpoint;
innodb_flush_log_at_trx_commit配置
参数决定了事务提交时的行为。0:代表每一次提交只是写入到redo log buffer,如果mysql进程挂了,会丢数据,这是不安全的;1:代表每一次提交都写入磁盘,fsync;2:代表每一次提交都写入操作系统写缓冲,write,如果操作系统挂了,会丢数据;
两段式提交
redo log与binlog需要两段式提交,防止只有一个写入成功,这样会出现数据不一致;如果只有redo log成功,从库不一致;反之,主库不一致;
大致过程:
redo log prepare;
binglog write;
commit;
如何刷脏页?
不能只用redo log,还需要将对应的页读入内存,然后使用redo log更新内存,再刷磁盘;