• 详解 MySQL 重做日志 redolog

详解 MySQL 重做日志 redolog

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

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