• 详解 MySQL 重做日志 redolog

详解 MySQL 重做日志 redolog

2025-05-14 08:37:05 栏目:宝塔面板 24 阅读

redo log也就是所谓的重做日志,是innoDb存储引擎独有的日志,它使得MySQL在宕机情况下依旧可以redo log完成数据具备恢复能力, 从而保证数据完整性,本文将针对该日志进行分析讲解,希望对你有帮助。

redolog的作用

redo log是InnoDB存储引擎独有的日志,用于MySQL工作过程中崩溃或者宕机时进行数据恢复的文件,从而保证数据的持久性以及完整性。

redolog是如何运行工作的

我们都知道数据库数据基本单位也是和操作系统一致的,都是以页为单位,我们以MySQL数据查询为例,为了尽可能减少IO次数,MySQL在进行数据查询会优先将数据查询并存储到buffer Pool中,在事务提交后将修改操作按照配置的刷盘机制写回磁盘中。

例如当我们需要对数据修改(update)操作时,基于buffer pool完成高效的数据更新操作后将事务提交,此时我们的redo日志数据就会按照innodb_flush_log_at_trx_commit指定的刷盘机制叫redolog缓存数据刷盘:

默认情况下redo日志对应的缓冲区大小为16M,该变量我们可以通过如下语句查看:

SHOW VARIABLES LIKE 'innodb_log_buffer_size';

对应查询结果如下:

Variable_name         |Value   |
----------------------+--------+
innodb_log_buffer_size|16777216|

redolog几个刷盘时机

上文图解的第四步提到了redo log刷盘的操作,当符合以下几种条件时,对应redo log buffer会被刷盘持久化到磁盘中:

  • 事务提交:当事务提交时,log buffer里redo log会按照innodb_flush_log_at_trx_commit的刷盘时机将数据持久化到磁盘中。
  • redo log buffer空间不足:log buffer中的redo log已经占满该缓冲区一半时,缓冲区数据就会被刷到磁盘中。
  • 事务日志缓冲区已满:InnoDB使用一个事务日志缓冲区(transaction log buffer)存储事务redo log的日志条目,当该缓存区已满时,就会触发日志刷新将日志写入磁盘中。
  • 后台线程定时刷盘:innodb后台线程会每隔1s调用操作系统fsync函数将redolog数据刷盘。
  • checkpoint:线程会定时执行一个checkpoint,将buffer pool已经刷盘持久化到物理文件的数据对应的redo log设置为可被覆盖(保证日志空间可以循环复用),这期间对应的redo log数据就会被写入磁盘中。
  • 服务器关闭:MySQL服务正常关闭时,这些缓冲区的数据就会写入到磁盘中。

redo log的刷盘策略

上文事务提交时提到一个刷盘策略的概念,实际上写入磁盘的时机是由MySQL系统参数设置决定的,我们可以键入下面这条SQL查看innodb_flush_log_at_trx_commit这个参数的设定值:

SHOW VARIABLES LIKE 'innodb_flush_log_at_trx_commit';

以笔者的MySQL8为例,默认情况下这个参数值为1:

当这个值为0时,每次进行修改写入到redo log buffer,然后redo log buffer会将数据写到page cache中,由log thread每个1s调用操作系统函数fsync将数据写入到redo.file中。很可能因为服务器崩溃或者宕机导致丢失1s的数据。

1为默认值,当参数值设置为1时, 每次进行修改操作后将数据写入到redo log buffer中,一旦事务被提交,就会自动调用操作系统函数fsync将数据写入的磁盘中的redo.file文件中。若设置为这个级别,当服务器宕机,若当前事务没有提交,这部分数据丢失也无妨,事务提交的话,那么这个操作就会被写到磁盘中,照样可以恢复。

配置为2时,每当事务提交后,redo log就会刷入内核缓冲区,这些数据具体何时刷盘则交由操作系统决定,这种情况在MySQL宕机情况下不会造成数据丢失,一旦操作系统崩溃则可能会造成内核缓冲区的redo log数据丢失,导致进行数据备份还原时丢失一部分数据:

redo log的日志文件组

redo log并不是单指一个文件,它是由一组日志文件构成的,如下图所示,这些文件大小都是一样的,写入操作时依次从从1开始写,文件1写满了,就将数据写到文件2,最后写到文件4。

redolog通过write pos标记当前写入的位置,每次完成写入write pos标志位后移,一旦write pos和checkpoint相遇时就说明文件满了,此时innodb就会通过让checkpoint往后移进行一些空间数据擦除,以此来保证一个足够空间容纳新数据。

为什么InnoDB不直接将数据写入磁盘

页是操作系统的基本单位,一页差不多16kb,而我们每次操作的数据可能也就x byte,为了x byte的数据操作将一页的数据进行同步持久化实在有些大材小用了,所以通过redo log buffer记录修改内容,通过刷盘策略进行数据刷盘更新,由此提升数据库的并发能力:

bin.log和redo.log对应的二阶段提交

经常有读者面试被问道的为什么我有了redo.log,你还需要bin log呢?而且这两个日志我到底要先写哪个才能保证主从数据库的一致性呢?

对此我们不妨用反正法来说明:

  • 假设我们先写bin.log,当事务提交后bin.log写入成功,结果再写redo.log期间,数据库挂了。重启恢复后,主数据库根据早期redo.log(我们的redo.log没写入)恢复到bin log写入前的样子,而从数据库已经根据bin.log同步到了一份数据,最终从数据库比主数据库多了一条数据。

  • 我们再假设写redo log,假设事务执行期间我们就写了redo log,在事务提交之后写bin log数据库挂了,我们重启数据库后主主库恢复。主库根据redo log进行灾备恢复,将我们更新的数据同时恢复回来,而从库根据bin log进行数据同步时,并没有察觉到主库刚刚写入的数据,这就导致了从库比主库少了一条数据。

所以MySQL设计者提出了二阶段提交的概念,整体步骤为:

  • 在事务开始时,先写redo-log(prepare)。
  • 事务提交时,再写bin log。
  • 事务提交成功,再写redo-log(commit)。

有了这样一个整体步骤我们不妨用两种情况来举个例子演示一下二阶段提交如何保证数据一致性。

假设我们有一张user表,这张表只有id、name两个字段。我们执行如下SQL:

update user set name='aa' where id=1;

假如我们在redo.log提交时数据库宕机,二阶段是如何保证数据一致性的呢?

首先数据库重启恢复,然后主库发现redo.log日志处于prepare而且bin.log也没有写入,所以一切恢复到之前的样子(事务回滚),而从库对此无感,同步时也是同步成操作失败之前的样子,一切风平浪静:

假如我们bin.log进行commit成功之后数据库宕机,二阶段提交是如何保证数据库一致性的呢?还是老规矩:

  • 数据库重启恢复,然后主库发现bin.log有个commit成功的数据(事务是完整的)
  • 然redo.log处于prepare阶段,但是我们还是可以根据情况推断出有个当前主库有个commit成功的事务,所以redo.log会根据bin.log将redo.log设置为commit
  • 从库已根据主库的bin.log发现有新增一条新数据,由此同步一条更新数据,双方都有了一条新数据,数据库一致性由此保证:

本文地址:https://www.yitenyun.com/207.html

搜索文章

Tags

数据库 API FastAPI Calcite 电商系统 MySQL 数据同步 ACK 双主架构 循环复制 Web 应用 异步数据库 序列 核心机制 生命周期 Deepseek 宝塔面板 Linux宝塔 Docker JumpServer JumpServer安装 堡垒机安装 Linux安装JumpServer esxi esxi6 root密码不对 无法登录 web无法登录 Windows Windows server net3.5 .NET 安装出错 宝塔面板打不开 宝塔面板无法访问 SSL 堡垒机 跳板机 HTTPS Windows宝塔 Mysql重置密码 无法访问宝塔面板 HTTPS加密 查看硬件 Linux查看硬件 Linux查看CPU Linux查看内存 ES 协同 修改DNS Centos7如何修改DNS scp Linux的scp怎么用 scp上传 scp下载 scp命令 防火墙 服务器 黑客 Serverless 无服务器 语言 存储 Oracle 处理机制 Spring SQL 动态查询 Linux 安全 网络架构 工具 网络配置 加密 场景 开源 PostgreSQL 存储引擎 RocketMQ 长轮询 配置 HexHub Canal MySQL 9.3 Rsync 架构 InnoDB 缓存方案 缓存架构 缓存穿透 信息化 智能运维 响应模型 日志文件 MIXED 3 线上 库存 预扣 索引 数据 业务 监控 AI 助手 数据库锁 单点故障 聚簇 非聚簇 B+Tree ID 字段 云原生 分库 分表 Redis Redis 8.0 GreatSQL Hash 字段 DBMS 管理系统 SpringAI 自定义序列化 优化 万能公式 openHalo OB 单机版 数据集成工具 SQLite Redka ​Redis 机器学习 推荐模型 SVM Embedding PostGIS 系统 SQLark 虚拟服务器 虚拟机 内存 分页查询 Netstat Linux 服务器 端口 自动重启 运维 sqlmock • 索引 • 数据库 RDB AOF 排行榜 排序 Testcloud 云端自动化 查询 EasyExcel MySQL8 prometheus Alert SQLite-Web 数据库管理工具 同城 双活 缓存 sftp 服务器 参数 共享锁 OAuth2 Token Entity 开发 StarRocks 数据仓库 技术 向量数据库 大模型 不宕机 容器化 Postgres OTel Iceberg 分布式架构 分布式锁​ 聚簇索引 非聚簇索引 数据类型 Doris SeaTunnel 人工智能 推荐系统 IT运维 分页 数据结构 连接控制 机制 AIOPS IT 数据备份 MongoDB 容器 Caffeine CP Python Web 部署 LRU Milvus 向量库 悲观锁 乐观锁 Ftp 池化技术 连接池 redo log 重做日志 崖山 新版本 高可用 mini-redis INCR指令 磁盘架构 流量 MCP 单线程 线程 MVCC 事务隔离 开放协议 Web 接口 字典 电商 原子性 对象 微软 SQL Server AI功能 速度 服务器中毒 数据脱敏 加密算法 R2DBC QPS 高并发 窗口 函数 双引擎 RAG HelixDB 主库 ZODB Order SSH 频繁 Codis Crash 代码 1 PG DBA 引擎 性能 List 类型 网络 dbt 数据转换工具 工具链 优化器 Pottery 意向锁 记录锁 InfluxDB 模型 传统数据库 向量化 发件箱模式 事务同步 网络故障 UUIDv7 主键 仪表盘 Redisson 锁芯 线程安全 INSERT COMPACT Undo Log LLM JOIN 连接数 订单