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,这就是两阶段提交。

相关推荐
程序员不想YY啊15 分钟前
MySQL元数据库完全指南:探秘数据背后的数据
数据库·mysql·oracle
柏油2 小时前
MySql InnoDB 事务实现之 undo log 日志
数据库·后端·mysql
jack xu13 小时前
高频面试题:如何保证数据库和es数据一致性
java·大数据·数据库·mysql·elasticsearch
炫彩@之星4 小时前
Mysql之UDF提权
mysql·udf提权
爱的叹息4 小时前
DeepSeek 大模型 + LlamaIndex + MySQL 数据库 + 知识文档 实现简单 RAG 系统
数据库·人工智能·mysql·langchain
橘猫云计算机设计4 小时前
net+MySQL中小民营企业安全生产管理系统(源码+lw+部署文档+讲解),源码可白嫖!
数据库·后端·爬虫·python·mysql·django·毕业设计
黄嚯嚯4 小时前
Mysql8.0 推出的强大功能 窗口函数(Window Functions)
数据库·mysql
神仙别闹5 小时前
基于Java+MySQL 实现(Web)日程管理系统
java·前端·mysql
苹果酱05675 小时前
2020-06-23 暑期学习日更计划(机器学习入门之路(资源汇总)+概率论)
java·vue.js·spring boot·mysql·课程设计
Lucky GGBond6 小时前
MySQL 报错解析:SQLSyntaxErrorException caused by extra comma before FROM
数据库·mysql