%% # 纲要 > 主干纲要、Hint/线索/路标 # Q&A #### 已明确 #### 待明确 > 当下仍存有的疑惑 **❓<font color="#c0504d"> 有什么问题?</font>** %% # MySQL 中的日志类型 主要日志类型包括[^1]: | 日志类型 | 日志名 | 作用 | 所属层 | | --------- | ----------------- | ---------------------------------------------- | ------------- | | **二进制日志** | binog | 记录所有**修改操作**(DDL、DML),主要用于**数据备份/恢复**、**主从复制** | Server 层 | | **错误日志** | error log | 记录 MySQL 服务器启动、运行、关闭过程中的**错误信息** | Server 层 | | **查询日志** | general query log | 记录所有**客户端请求(连接 & 执行的 SQL 语句**) | Server 层 | | **慢查询日志** | slow query log | 记录**执行时间超过阈值的 SQL 语句**,常用于性能分析 | Server 层 | | **审计日志** | audit log | 记录用户的访问行为和操作,用于安全审计和合规性需求。 | Server 层 | | **中继日志** | relay log | 用于**主从复制**,从库接收主库的 binlog | Server 层 | | | | | | | **重做日志** | redo log | 记录数据变更,结合 WAL 机制 用于实现事务的 "**持久性**", | 存储引擎层(InnoDB) | | **回滚日志** | undo log | 记录修改前旧值,用于**事务回滚** 和 **MVCC**,实现事务中的**原子性** | 存储引擎层(InnoDB) | <br><br> # Undo Log 回滚日志 Undo log 记录了事务执行过程中,**修改前的旧数据**,主要用于 "**事务回滚**" 和 **MVCC** 机制: 1. 实现**事务回滚**,保证事务的 "**==原子性==**"。 - 当事务执行过程中 **意外崩溃** 或者 **主动 `ROLLBACK`** 时,通过 Undo Log 将**已执行过的操作撤销**,回滚到事务开始前的状态。 2. 用于 **MVCC 机制**,实现 "**读已提交**" 和 "**可重复读**" 隔离级别 - 参见 [[02-开发笔记/08-数据库/MySQL 相关/MySQL 事务#MVCC 机制|MySQL 事务-MVCC机制]],结合 ReadView 控制,沿着**版本链**找到满足可见性的记录。 Undo log 记录信息的方式大致理解为: - **插入**数据时,记录其**主键**,回滚时则**按主键删除**; - **删除**数据时,记录其**内容**,回滚时**重新插入**; - **更新**数据时,记录其**旧值**,回滚时重新**更新为旧值**。 > [!NOTE] 版本链示例[^2] > ![[_attachment/02-开发笔记/08-数据库/MySQL 相关/MySQL 日志.assets/IMG-MySQL 日志-E94A218C175E63E9612BF53F26CB39D6.png|611]] > > [!note] 事务回滚示意[^2] > ![[_attachment/02-开发笔记/08-数据库/MySQL 相关/MySQL 日志.assets/IMG-MySQL 日志-FE44A4E185D52FB685C23BA1BE71645F.png|255]] <br><br> # Redo Log 重做日志 Redo log 记录了**事务修改操作**(**修改后的数据状态**),用于保障 **事务的==持久性==**。 ## Redo log 的工作机制 redo log 包括两部分: - **内存中的 redo log buffer**:临时缓存 redo 日志内容。 - **磁盘上的 redo log file**:真正的 **redo log 日志文件**,默认是 `ib_logfile0` 和 `ib_logfile1`,采用循环写入。 在事务执行过程中,会**将对应 redo log 内容记录到==内存的 redo log buffer== 中**。 在**事务提交**时,完成 **redo log 的==持久化==**——将 redo log buffer 中内容写入磁盘上的 redo log 文件。 > [!note] redo log 持久化示意 > ![[_attachment/02-开发笔记/08-数据库/MySQL 相关/MySQL 日志.assets/IMG-MySQL 日志-BB3E69AF41586A786A7B02036E3AE9F2.png|569]] > [!info] `innodb_flush_log_at_trx_commit` 参数控制 redo log 的刷盘行为 > > - `1`(默认):每次**事务提交**都刷盘——向磁盘日志文件写入,且**执行 `fsync()` 刷入磁盘**,确保日志持久化。(缺点是需等待磁盘同步完成) > - `2`:**事务提交时**向磁盘日志文件写入,但**不执行 `fsync()`**,日志可能留在 **OS 的页缓存(Page Cache)中**。 > - `0`:**不立即同步**。(由 InnoDB 后台线程定期将 redo log buffer 中内容写入磁盘) > > 三种值的差异: > > ![[_attachment/02-开发笔记/08-数据库/MySQL 相关/MySQL 日志.assets/IMG-MySQL 日志-8DFFB47163EF8B087C70CF24FDF67FD8.png|611]] > > [!NOTE] redo log 只在 "事务提交时" 才持久化到磁盘,是 "顺序写",磁盘 I/O 性能更高。 <br> ## WAL 机制 InnoDB 中采用 **==WAL==(Write-Ahead Logging,预写日志) 机制**,搭配 Redo Log 保障**事务持久性**,实现崩溃恢复。 WAL 机制:**修改数据页时,先将相应的 redo log 写入磁盘,再将数据页本身写入磁盘。** 工作流程如下: 1. 事务过程中,**执行修改操作**(增删改),InnoDB 会进行: - **修改 Buffer Pool 中数据页**,标记为 "**==脏页==**"。 - **生成相应 redo log 记录,写入内存中 redo log buffer** 2. 事务提交时,将 redo log buffer 中内容**写入到磁盘的 redo log 文件**,**默认保证==刷盘==**; 3. 后台线程在 **==异步==** 将 Buffer Pool 中 "脏页" 刷入磁盘。 由此,若数据库崩溃时脏页还未写入磁盘,只要 **redo log 已持久化到磁盘**,就能**恢复事务提交时的修改**。 > [!NOTE] WAL 机制示意[^2] > ![[_attachment/02-开发笔记/08-数据库/MySQL 相关/MySQL 日志.assets/IMG-MySQL 日志-C7BDEDFB325FF4A8AEFB73426F77D5D2.png|722]] <br><br><br> # Binlog 二进制日志 binlog 是 MySQL 中 **Server 层** 的日志,记录了**所有数据变更操作**,主要用于**数据备份恢复**、**主从复制**。 > [!info] binlog 是全量记录,每写满一个文件就滚动到新文件继续写,不覆盖旧日志。 ### binlog 格式类型 三种格式:STATEMENT(默认)、ROW、MIXED | 格式类型 | 说明 | | --------- | --------------------------- | | STATEMENT | 记录 "**逻辑操作**"(即 SQL 语句) | | ROW | 记录 "**行数据变更结果**" | | MIXED | 根据情况自动使用 STATEMENT 或 ROW 模式 | # 主从复制 MySQL 的主从复制依赖于 binlog,该日志记录 MySQL 上的所有修改操作,复制过程就是**将主库中 binlog 里记录的操作在从库上回放执行一遍**,从而保证从库与主库数据一致。 ![[_attachment/02-开发笔记/08-数据库/MySQL 相关/MySQL 日志.assets/IMG-MySQL 日志-A8D0FC0A267BD2D7C71BA5B6EA0548A6.png|721]] 具体过程: 1. 主库 **写入 binlog** - 主库在收到客户端 "**==事务提交==**" 请求时,**先将事务操作写入 binlog,再提交事务更新数据**。 2. 从库 **接收 binlog** - 从库中一个独立的 I/O 线程连接主库,**接收主库的 binlog 日志**,并**写入到 ==从库的 relay log== 中继日志**中。 3. 从库 **应用 binlog** - 从库中一个独立线程**读取 relay log**,按序应用其中操作。 ### 主从复制的同步模式 三种模式: - **异步复制**(Asynchronous Replication) - MySQL 的默认模式,主库提交事务后,**不会等待 binlog 同步到各个从库**,而是直接向客户端返回响应。一旦主库宕机,就会丢失数据。 - **半同步复制**(Semi-Synchronous Replication) - MySQL 5.7 引入,该模式下,主库提交事务后,**==至少等待一个从库==完成 binlog 接收**,才会向客户端返回响应。即使主库宕机,**保证至少还有一个从库存有最新数据**。 - **同步复制**(Synchronous Replication) - 该模式下,主库提交事务后,**必须等待所有从库均完成 binlog 接收**,才向客户端返回响应。 %% # 查看日志 ```sql -- 查看二进制日志 SHOW BINARY LOGS; -- 查看所有 binlog 文件 SHOW BINLOG EVENTS IN 'mysql-bin.000001'; -- 查看具体 binlog 内容 -- 查看 Redo Log 状态 SHOW ENGINE INNODB STATUS; -- 查看 Undo Log 状态 SHOW ENGINE INNODB STATUS; ``` %% <br><br><br> # Buffer ## 闪念 > sudden idea ## 候选资料 > Read it later # ♾️参考资料 - [MySQL 日志:undo log、redo log、binlog 有什么用? \| 小林coding](https://xiaolincoding.com/mysql/log/how_update.html#%E4%B8%BA%E4%BB%80%E4%B9%88%E9%9C%80%E8%A6%81-undo-log) # Footnotes [^1]: [MySQL 中的日志类型有哪些?binlog、redo log 和 undo log 的作用和区别是什么? - 面试鸭 - 程序员求职面试刷题神器](https://www.mianshiya.com/question/1772575207802904578) [^2]: [MySQL 日志:undo log、redo log、binlog 有什么用? \| 小林coding](https://xiaolincoding.com/mysql/log/how_update.html#%E4%B8%BA%E4%BB%80%E4%B9%88%E9%9C%80%E8%A6%81-undo-log)