redolog与binlog的写入机制

redo log

事务在执行的过程中,生成的redo log是要先写到redo log buffer中的。redo log buffer里面的内容不需要每次生成后都直接持久化到磁盘。

如果事务执行期间MySQL发生异常重启,那这部分日志就丢了,但是由于没有commit,所以丢了也不会有损失。

不过,事务没commit时,redo log buffer却有可能持久化到磁盘

redo log可能存在的三个状态

  1. 存在redo log buffer中,物理是在MySQL进程中
  2. 写到磁盘(write),但是没有持久化(fsync),物理上是在文件系统的page cache中
  3. 持久化到磁盘,物理上是在hard disk中

写redo log buffer是很快的,write到page chche也差不多,但是fsync的速度就慢很多了

InnoDB提供了innodb_flush_log_at_trx_commit参数用于控制redo log的写入策略

  1. 设置为0,每次commit都只把redo log留在redo log buffer
  2. 设置为1,每次commit都将redo log持久化到hard disk
  3. 设置为2,每次commit都只把redo log写到page cache

InnoDB有一个后台线程,每间隔1s就会把redo log buffer中的日志,调用write写到page cache,然后调用fsync持久化到hard disk

注意,事务执行中的redo log也是直接写到redo log buffer中的,这些redo log也会被一起持久化到hard disk。也就是说一个没有commit的事务的redo log也是可能已经fsync到hard disk的

除此以外,还有两种场景会让没有commit的事务的redo log fsync到hard disk中

  1. redo log buffer占用空间即将达到innodb_log_buffer_size一半的时候,后台线程会主动写盘。只是write,没有fsync
  2. 并行的事务commit时,顺带将这个事务的redo log buffer持久化到hard disk

binlog

事务执行过程中,先把日志写到binlog cache,事务commit时,再把binlog cache写到binlog文件中

一个binlog是不能被拆开的,因此无论事务多大也要一次性写入。这也就涉及到了binlog cache的保存问题

系统给binlog cache分配了一片内存,每个线程一个,参数binlog_cache_size控制单个线程内binlog cache所占内存的大小。如果超过了这个参数,就要暂存到磁盘。

事务commit时,执行器把binlog cache里的完成事务写到binlog中,并情况binlog cache

每个线程有自己的binlog cache,但是共用同一份binlog文件

  1. write操作是写入page cache,没有把数据持久化到hard disk,速度较快
  2. fsync操作,将数据持久化到hard disk。占磁盘的IOPS

write和fsync的时机,是由参数sync_binlog控制的

  1. 设置为0时,每次只write,不sync
  2. 设置为1时,每次都fsync
  3. 设置为N时,表示每次都write,累积N个后fsync

因此,在出现IO瓶颈的场景中,将sync_binlog设置为一个比较大的值,一般为100---1000,对应的风险是有可能会丢失最近的N个日志

binlog与redo log的区别

  1. redo log是InnoDB引擎持有的,binlog是MySQL的Server层实现的,所有引擎都可以使用
  2. redo log是物理日志,记录的是"在某个数据页上做了什么修改";binlog是逻辑日志,记录的是这个语句的原始逻辑,比如"给ID为2这一行的c字段+1"
  3. redo log是循环写的,空间固定会用完;binlog是可以追加写入的

有了对这两个日志的概念性理解,执行这个update语句的内部流程

  1. 执行器先找引擎取ID=2这一行。ID是主键,引擎直接用树搜索到这一行。如果ID=2这一行所有的数据页本来就在内存中,就直接返回给执行器;否则,需要先从磁盘读入内存,然后再返回。
  2. 执行器拿到引擎给的行数据,把这个值加上1,得到一行新的数据,再调用引擎接口写入这行新数据。
  3. 引擎将这行新数据更新到内存中,同时将这个更新操作记录到redo log里面,此时redo log处于prepare状态。然后告知执行器执行完成了,随时可以提交事务。
  4. 执行器生成这个操作的binlog,并把binlog写入磁盘。
  5. 执行器调用引擎的提交事务接口,引擎把刚刚写入的redo log改成提交(commit)状态,更新完成。

流程图如下,浅色表示在InnoDB内部执行,深色表示在执行器中执行。

最后三步将redo log的写入拆成了两个步骤:prepare和commit,这就是两阶段提交。

相关推荐
Sunyanhui125 分钟前
牛客网 SQL36查找后排序
数据库·sql·mysql
老王笔记39 分钟前
MHA binlog server
数据库·mysql
2401_871213302 小时前
mysql高阶语句
数据库·mysql
山山而川粤4 小时前
网络安全宣传系统|Java|SSM|JSP|
java·开发语言·后端·学习·mysql
_汤姆大叔5 小时前
MySQL 高级操作全解析
数据库·mysql
呼啦啦啦啦啦啦啦啦6 小时前
【MySQL篇】聚合查询,联合查询
数据库·mysql
今天不coding7 小时前
MySQL体系架构
数据库·mysql·体系架构·网络连接层·服务层·存储引擎层·系统文件层
奥顺互联V9 小时前
一次性部署:使用Docker部署PHP应用
大数据·mysql·开源·php
小黄人软件9 小时前
20241220流水的日报 mysql的between可以用于字符串 sql 所有老日期的,保留最新日期
数据库·sql·mysql
无为之士9 小时前
Linux自动备份Mysql数据库
linux·数据库·mysql