• 详解 MySQL 重做日志 redolog

详解 MySQL 重做日志 redolog

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

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 Web 应用 异步数据库 数据同步 ACK 双主架构 循环复制 JumpServer SSL 堡垒机 跳板机 HTTPS TIME_WAIT 运维 负载均衡 HexHub Docker JumpServer安装 堡垒机安装 Linux安装JumpServer Deepseek 宝塔面板 Linux宝塔 生命周期 esxi esxi6 root密码不对 无法登录 web无法登录 服务器 管理口 序列 核心机制 Windows Windows server net3.5 .NET 安装出错 HTTPS加密 服务器性能 查看硬件 Linux查看硬件 Linux查看CPU Linux查看内存 宝塔面板打不开 宝塔面板无法访问 开源 PostgreSQL 存储引擎 Windows宝塔 Mysql重置密码 Oracle 处理机制 无法访问宝塔面板 连接控制 机制 InnoDB 数据库锁 监控 Serverless 无服务器 语言 Spring Redis 异步化 ES 协同 技术 group by 索引 SQL 优化 万能公式 Undo Log 分页查询 缓存方案 缓存架构 缓存穿透 高可用 动态查询 GreatSQL 连接数 机器学习 工具 响应模型 查询 日志文件 MIXED 3 scp Linux的scp怎么用 scp上传 scp下载 scp命令 R edis 线程 SVM Embedding 加密 场景 R2DBC 锁机制 数据 主库 Netstat Linux 服务器 端口 openHalo Linux 安全 Postgres OTel Iceberg 云原生 RocketMQ 长轮询 配置 ​Redis 推荐模型 SQLite-Web SQLite 数据库管理工具 Recursive 自定义序列化 存储 AI 助手 SQLark 共享锁 Hash 字段 向量数据库 大模型 PG DBA Ftp 电商 系统 OB 单机版 架构 启动故障 国产数据库 MySQL 9.3 修改DNS Centos7如何修改DNS 数据分类 • 索引 • 数据库 人工智能 推荐系统 流量 Rsync sftp 服务器 参数 防火墙 黑客 线上 库存 预扣 redo log 重做日志 磁盘架构 分库 分表 同城 双活 信息化 智能运维 Python mini-redis INCR指令 业务 不宕机 聚簇 非聚簇 向量库 Milvus MVCC Canal PostGIS 传统数据库 向量化 行业 趋势 缓存 Redisson 锁芯 高效统计 今天这篇文章就跟大家 INSERT COMPACT 网络架构 网络配置 Doris SeaTunnel prometheus Alert 数据备份 filelock 虚拟服务器 虚拟机 内存 事务 Java 开发 语句 Web 窗口 函数 ZODB 数据脱敏 加密算法 MongoDB 数据结构 RDB AOF 读写 引擎 性能 容器 核心架构 订阅机制 Go 数据库迁移 失效 OAuth2 Token IT运维 自动重启 数据类型 频繁 Codis B+Tree ID 字段 模型 Redis 8.0 容器化 分布式 集中式 崖山 新版本 发件箱模式 网络故障 SSH 微软 SQL Server AI功能 MCP 开放协议 DBMS 管理系统 聚簇索引 非聚簇索引 播客 SpringAI Web 接口 部署 QPS 高并发 JOIN Entity 数据页 速度 服务器中毒 Caffeine CP 原子性 排行榜 排序 数据集成工具 网络 Pottery StarRocks 数据仓库 工具链 Testcloud 云端自动化 池化技术 连接池 Redka 主从复制 代理 事务隔离 分布式架构 分布式锁​ 分页方案 排版 1 大表 业务场景 dbt 数据转换工具 悲观锁 乐观锁 LRU 分页 AIOPS 日志 优化器 EasyExcel MySQL8 单点故障 sqlmock Order 意向锁 记录锁 仪表盘 数据字典 兼容性 事务同步 InfluxDB UUIDv7 主键 对象 单线程 RAG HelixDB Ansible ReadView UUID ID 订单 Crash 代码 IT 双引擎 LLM 字典 Weaviate 编程 Valkey Valkey8.0 恢复数据 产业链 千万级 MGR 分布式集群 分布式锁 Zookeeper 线程安全 Pump List 类型 关系数据库 拦截器 动态代理 表空间 Next-Key 解锁 调优 慢SQL优化 快照读 当前读 视图 RR 互联网 GitHub Git 神经系统 矢量存储 数据库类型 AI代理 国产 用户 算法 查询规划 count(*) count(主键) 行数 技巧 CAS 并发控制 恢复机制 多线程 闪回