[go: up one dir, main page]

日志(Redo Log、Undo Log、Binlog)

目录

背景知识:

Redo Log(重做日志)

Undo Log(回滚日志)

支持实现多版本并发控制MVCC 的原理:

如何理解MVCC

BinLog(二进制日志)

BinLog的三种格式

三大日志的核心作用


背景知识:

  1. MySQL 分为两层 : Server 层(负责 MySQL 功能)和 存储引擎层(负责数据存储)
  2. Redo Log 和 Undo Log 属于存储引擎层 InnoDB引擎 的日志,其他引擎是没有的
  3. Binlog 是属于 Server 层的日志

Redo Log(重做日志)

问题引入

  • 如果MySQL的每一次修改数据都需要写入磁盘,那么每一次操作就对应着一次磁盘IO,成本很高。
  • 如果MySQL的每一次修改数据都将脏页暂存在内存里,然后延迟异步刷盘,可能系统突然崩溃,导致内存的脏页数据丢失,此时就不能保证事务的持久性。

脏页:内存中被修改,但尚未同步到磁盘的数据页

解决方案:为了解决上述问题,既要保证性能,又要保证持久性,MySQL的设计者就采用了WAL技术,WAL即 Write-Ahead Logging,关键点是 先写日志, 写的就是RedoLog日志

在事务提交时,将日志写入Redo Log磁盘文件,记录下数据页的物理修改。当系统突然崩溃时,脏页数据丢失,可以根据Redo Log找回脏页数据

问题

那么 直接把脏页数据写入磁盘把日志记录写入磁盘 不都是一次磁盘IO吗?为什么选择后者?

RedoLog 是固定大小的文件,以循环的方式写入,不断覆盖最早的内容

因为 把脏页数据写入磁盘是随机IO,而把日志记录写入RedoLog文件中是顺序IO

顺序IO效率远大于随机IO

  • 记录的内容:数据页的物理修改
  • 写入时机:事务提交时
  • 用途:保证事务的持久性

假设执行一条 SQL:

UPDATE accounts SET balance = balance - 100 WHERE id = 1;

  1. InnoDB 找到 id=1 的数据所在的数据页(假设是页 5)。
  2. 修改页 5 中的 balance 字段值(从 500 改为 400)。
  3. 生成一条 redo log,记录:“页 5 的偏移位置 X,值从 500 变为 400”。
  4. 事务提交时,redo log 被刷盘,但数据页可能仍在内存中(未刷盘)。
  5. 若此时数据库崩溃,重启后通过 redo log 重放,将页 5 的修改重新应用到磁盘。

Undo Log(回滚日志)

用途:保证事务的原子性 和 支持实现MVCC(多版本并发控制)

保证事务原子性的原理:

Undo Log 是逻辑日志,记录了数据修改操作的“反向操作”,当事务需要回滚时,MySQL可以通过反向操作将数据恢复到事务开始时的状态,从而保证事务的原子性。

比如,如果一个事务修改了一行数据,将某列的值从 100 修改为 200,Undo Log 会记录一个反向操作,表示将 200 恢复为 100,从而撤销这一修改。

支持实现多版本并发控制MVCC 的原理:

Undo Log 记录了数据的版本链

1.版本链的构建:

  • 每次修改数据行时,会生成一个 Undo Log 记录,包含:
    • 旧版本的数据镜像
    • 事务 ID(trx_id):标识生成该版本的事务。
    • 回滚指针(roll_pointer):指向更早版本的 Undo Log。
  • 多个版本通过 roll_pointer 形成链表结构,称为版本链

2.MVCC 的读操作:

  • 当某事务需要读取数据时,InnoDB 会根据当前事务的视图(ReadView)的信息与数据版本的trx_id去比较,从而判断哪些版本可见,如果最新版本不可读,则会根据 Undo Log 的版本链去获得上一版本的数据
如何理解MVCC

背景知识:

  • MySQL会为每个事务分配一个事务ID,事务ID按事务创建顺序递增

MVCC多版本并发控制,核心思想:维护一个数据的多个版本,使得读写操作没有冲突,避免加锁阻塞

典型应用:MySQL 的 InnoDB 存储引擎通过 MVCC 实现 读已提交可重复读 隔离级别。

MVCC的实现依赖于

  • 数据库记录行的隐藏字段 trx_id 事务id 和 roll_pointer 指针
  • ReadView读视图
  • UndoLog版本链

实现原理:

首先,InnoDB 在事务开启后执行第一个查询时,会创建一个快照(称之为ReadView),这个ReadView包含了以下信息:

m_ids: 活动事务id列表(活动事务指的是已经开始、尚未提交/回滚的事务)

min_trx_id: 最小活动事务id

min_trx_id 是 ReadView 创建时 “所有活跃事务的最小 ID”—— 若某个事务的 ID 比 min_trx_id 还小,说明它在所有活跃事务之前就结束了(已提交 / 回滚),其修改的数据是 “稳定的”

max_trx_id: 最大活动事务id

creator_trx_id: 当前事务id

紧接着 InnoDB 会通过查询语句定位到最新版本的数据行,并根据以下规则获取到可以访问的数据版本:

  • 如果被访问版本的trx_id 事务id等于ReadView中的当前事务id,表明当前事务在访问自己修改过的记录,即可以读取到该版本的数据;
  • 如果被访问版本的trx_id 事务id小于ReadView中的最小活动事务id,表明生成该版本的事务在当前事务生成ReadView前已经提交,即可以读取到该版本的数据;
  • 如果被访问版本的trx_id 事务id大于或等于ReadView中的最大活动事务id,表明生成该版本的事务在当前事务生成ReadView后才开启,此时该版本不可以被当前事务访问,需要通过隐藏的回滚指针从undo log中读取历史版本;
  • 如果被访问版本的trx_id 事务id,在ReadView的 最小活动事务id 和 最大活动事务id 之间,则需要判断 trx_id 事务id 是否在活动事务列表中
    • 如果在:说明ReadView创建时,创建该版本数据的事务还未提交,因此需要通过回滚指针读取历史版本并返回;
    • 如果不在:说明ReadView创建时,创建该版本数据的事务已经提交,所以可以读取到该版本的数据。

读已提交隔离级别下:事务中的每次查询前都会创建一个新的ReadView。新建的ReadView会更新creator_trx_id以外的其余字段,因此不可重复读现象依然存在。

可重复读隔离级别下:只会在事务中的第一次查询时创建ReadView,同一个事务中后续所有的查询共用一个ReadView,由此便解决了不可重复读的问题。

ReadView的生成时机是不同的,这也是两个隔离级别有区别的根本原因

BinLog(二进制日志)

BinLog: 是记录所有数据库表结构变更 以及 表数据修改的二进制日志,不会记录Select和Show操作。

用途:数据备份、灾难恢复、主从同步

写入时机:事务提交时

BinLog的三种格式

MySQL 的BinLog支持三种格式: Statement、Row、Mixed

  • Statement
    • BinLog里面记录的是 SQL 语句原文
    • 这种格式有bug,例如使用now()等时间函数,导致主从同步后数据不相同
  • Row
    • BinLog里面记录的是 数据的具体变化
    • 例如 会记录修改的表名称、操作类型
      • Insert操作 Row格式会记录新插入的行的 所有字段列的值
      • Update操作 Row格式会记录行 更新前后的 所有字段列的值
      • Delete操作 Row格式会记录行删除前的 所有字段列的值
    • 优点:可以更好的保证主从数据同步时数据一致性,避免了STATEMENT格式中可能出现的不一致性问题
    • 缺点
      • 需要记录的内容更多,例如批量修改、插入等,就需要把每条记录都记录,存在性能问题
      • 文件体积大,在主从同步时,网络IO更高,耗费时间长
  • Mixed
    • 由MySQL根据具体情况自主选择使用Statement格式或Row格式来记录
    • 默认使用Statement格式,记录SQL语句
    • 在必要时候,对于某些可能导致主从不一致的SQL语句,自动使用Row格式,记录数据变更
    • 很好理解,这是为了平衡 性能和一致性

三大日志的核心作用

日志类型

核心作用

存储内容

所属组件

redo log

保证事务持久性(ACID 中的 D),崩溃恢复

物理日志:数据页的修改记录

InnoDB 存储引擎

undo log

保证事务原子性(ACID 中的 A),支持回滚

逻辑日志:事务修改前的反向操作

InnoDB 存储引擎

binlog

用于主从同步和时间点恢复(PITR)

逻辑日志:SQL 语句或行修改记录

MySQL 服务器层

分布式微服务企业级系统是一个基于Spring、SpringMVC、MyBatis和Dubbo等技术的分布式敏捷开发系统架构。该系统采用微服务架构和模块化设计,提供整套公共微服务模块,包括集中权限管理(支持单点登录)、内容管理、支付中心、用户管理(支持第三方登录)、微信平台、存储系统、配置中心、日志分析、任务和通知等功能。系统支持服务治理、监控和追踪,确保高可用性和可扩展性,适用于中小型企业的J2EE企业级开发解决方案。 该系统使用Java作为主要编程语言,结合Spring框架实现依赖注入和事务管理,SpringMVC处理Web请求,MyBatis进行数据持久化操作,Dubbo实现分布式服务调用。架构模式包括微服务架构、分布式系统架构和模块化架构,设计模式应用了单例模式、工厂模式和观察者模式,以提高代码复用性和系统稳定性。 应用场景广泛,可用于企业信息化管理、电子商务平台、社交应用开发等领域,帮助开发者快速构建高效、安全的分布式系统。本资源包含完整的源码和详细论文,适合计算机科学或软件工程专业的毕业设计参考,提供实践案例和技术文档,助力学生和开发者深入理解微服务架构和分布式系统实现。 【版权说明】源码来源于网络,遵循原项目开源协议。付费内容为本人原创论文,包含技术分析和实现思路。仅供学习交流使用。
在数据库系统(尤其是 MySQL)中,`binlog`、`redolog`、`undolog` 和 `relaylog` 是四种非常重要的日志类型,它们分别服务于不同的目的,保证了数据库的持久性、一致性、事务性和高可用性。下面逐一详细介绍这四种日志的作用、实现机制,并给出关键代码或配置示例。 --- ### 1. **Redo Log(重做日志)** #### ✅ 作用: - 用于**崩溃恢复(Crash Recovery)**,确保事务的**持久性(Durability)**。 - 记录物理级别的数据页修改,比如“在某个数据页的某个偏移量上写入了某些字节”。 - 属于 InnoDB 存储引擎特有,位于存储引擎层。 #### ✅ 工作原理: - 当事务提交时,InnoDB 会将修改先写入 `redo log buffer`,然后按一定策略刷到磁盘上的 `redo log file`。 - 即使数据库宕机,重启后可以通过重放 redo log 恢复未写入数据文件的已提交事务。 #### ✅ 配置参数(my.cnf): ```ini [mysqld] innodb_log_file_size = 256M innodb_log_files_in_group = 2 innodb_log_buffer_size = 16M ``` #### ✅ 示例:模拟 redo log 写入流程(伪代码) ```c // 简化版逻辑,实际由 InnoDB 实现 void write_redo_log(MTR *mtr) { // 开始一个 mini-transaction mtr_start(mtr); // 修改页面前,先写 redo 日志 log_write(LOG_PAGE_MODIFY, page_id, offset, new_data); // 刷日志到磁盘(根据 innodb_flush_log_at_trx_commit) if (flush_log_at_commit) { fflush(log_file); fsync(log_file); // 确保落盘 } mtr_commit(mtr); } ``` > ⚠️ 注意:Redo log 是环形写入,写满后覆盖旧日志(但必须确认对应数据已刷盘)。 --- ### 2. **Undo Log(回滚日志)** #### ✅ 作用: - 支持事务的**原子性(Atomicity)**和**MVCC(多版本并发控制)**。 - 记录数据修改前的旧值,用于事务回滚或提供历史版本读取。 #### ✅ 类型: - `INSERT UNDO`:插入操作的反向操作是删除,insert undo 在事务提交后可立即删除。 - `UPDATE/DELETE UNDO`:用于 MVCC,不能立刻清除,直到没有事务需要访问其快照。 #### ✅ 存储位置: - 存储在 `undo tablespace` 中(共享或独立表空间)。 #### ✅ 示例:undo log 结构(伪代码) ```c struct UndoLogRec { int op_type; // INSERT / UPDATE / DELETE Table* table; Row old_row; // 修改前的数据 RollPtr roll_ptr; // 指向前一条 undo 记录,形成链表 }; // 回滚时使用 void rollback_transaction(Transaction* trx) { for (each undo log record in trx) { switch(record->op_type) { case UPDATE: restore_row(record->table, record->old_row); break; case INSERT: delete_row(record->table, record->row_id); break; } } } ``` > 🔍 Undo log + Redo log 组合使用:undo log 本身也要记录 redo,以确保崩溃恢复时能正确重建 undo 链。 --- ### 3. **Binlog(Binary Log,归档日志)** #### ✅ 作用: - 属于 MySQL Server 层,记录所有**逻辑修改语句**(如 `INSERT`, `UPDATE`, `DELETE`),支持: - 数据复制(主从同步) - 数据恢复(基于时间点恢复 PITR) - 审计 #### ✅ 格式(格式由 `binlog_format` 控制): - `STATEMENT`:记录 SQL 语句(不推荐,可能导致主从不一致) - `ROW`:记录每一行的变化(最安全,推荐) - `MIXED`:混合模式 #### ✅ 启用 binlog(my.cnf): ```ini [mysqld] log-bin = /var/log/mysql/mysql-bin.log server-id = 1 binlog-format = ROW expire_logs_days = 7 ``` #### ✅ 查看 binlog 内容: ```bash mysqlbinlog --base64-output=DECODE-ROWS -v mysql-bin.000001 ``` #### ✅ 示例 binlog 内容(ROW 模式): ```sql ### UPDATE `test`.`users` ### WHERE ### @1=1 ### @2='Alice' ### SET ### @2='Bob' ``` > 🔄 Binlog 是主从复制的基础:主库写 binlog → 从库 IO Thread 拉取 → 写入 relay log → SQL Thread 回放。 --- ### 4. **Relay Log(中继日志)** #### ✅ 作用: - 仅存在于**从库(Slave)**,是主库 binlog 的副本。 - 用于解耦主库数据拉取与执行,提高复制性能和容错能力。 #### ✅ 工作流程: 1. 主库 binlog → 从库 IO Thread → 写入 relay log 2. 从库 SQL Thread 读取 relay log 并执行 #### ✅ 文件结构: - `relay-bin.000001`, `relay-bin.index` - 包含与 binlog 相同格式的内容 #### ✅ 关键参数: ```ini [mysqld] relay-log = /var/log/mysql/relay-bin relay-log-index = /var/log/mysql/relay-bin.index ``` #### ✅ 模拟 relay log 处理流程(伪代码): ```python def apply_relay_log(): while True: event = read_next_event_from_relay_log() if event.is_query(): execute_sql(event.sql) elif event.is_rows(): for row_change in event.changes: apply_row_change(row_change) update_slave_position() # 更新 master.info 或 GTID ``` > 💡 如果 relay log 损坏,可通过 `CHANGE MASTER TO ... RELAY_LOG_FILE=...` 手动修复。 --- ### 🔄 四种日志的关系图(简化) ``` +-----------+ +------------+ +-----------+ | Binlog |<----| Relay Log |<----| Master | +-----------+ +------------+ +-----------+ ↑ ↓ | ↓ | +--------------+ +---------> | SQL Thread | --> 数据更新 +--------------+ ↑ | +------------------+ | Redo Log | <-- 物理日志,InnoDB 崩溃恢复 | Undo Log | <-- 回滚 & MVCC +------------------+ ``` --- ### ✅ 总结对比表: | 日志类型 | 所属层次 | 作用 | 是否持久化 | 能否用于复制 | |------------|--------------|--------------------------|-------------|---------------| | Redo Log | InnoDB 引擎 | 崩溃恢复,持久性 | 是 | 否 | | Undo Log | InnoDB 引擎 | 回滚、MVCC | 是 | 否 | | Binlog | Server 层 | 归档、复制、恢复 | 是 | 是(主) | | Relay Log | Server 层 | 从库接收并中转主库日志 | 是 | 是(从) | --- ### ❗两阶段提交(Two-Phase Commit, 2PC)确保一致性 为了保证 `redo log` 和 `binlog` 的一致性,MySQL 使用 **XA 两阶段提交**: ```text 1. Prepare Phase: - 写 redo log(状态为 prepare) - 写 binlog 2. Commit Phase: - 写 redo log(状态为 commit) ``` 崩溃恢复时: - 若只有 prepare 状态的 redo log,且能在 binlog 中找到对应事务 → 提交 - 若 binlog 中找不到 → 回滚 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值