MySQL 日志详解


MySQL 日志详解

MySQL 使用多种日志来保证数据的一致性、可恢复性和可追溯性。这些日志在 MySQL 的运行过程中起着至关重要的作用。本文将详细介绍 MySQL 中各种日志的功能、实现原理和配置方法。


一、错误日志(Error Log)

功能说明

错误日志记录了 MySQL 服务器启动、运行和关闭过程中的错误信息、警告信息以及重要的诊断信息。这是排查 MySQL 问题的重要依据。

主要记录内容

  • MySQL 启动和关闭过程中的信息
  • 服务器运行过程中的错误信息
  • 事件调度器运行时的错误信息
  • 主从复制过程中的错误信息

配置方法

1
2
3
4
5
-- 查看错误日志位置
SHOW VARIABLES LIKE 'log_error';

-- 查看错误日志级别(MySQL 8.0+)
SHOW VARIABLES LIKE 'log_error_verbosity';
1
2
3
4
5
6
7
8
9
10
# my.cnf 配置
[mysqld]
# 错误日志文件路径
log-error=/var/log/mysql/error.log

# 错误日志级别(MySQL 8.0+)
# 1: 只记录错误
# 2: 记录错误和警告
# 3: 记录错误、警告和通知(默认)
log_error_verbosity=3

实现原理

错误日志由 MySQL 服务器进程直接写入文件系统,不经过存储引擎。日志写入是同步的,确保重要错误信息不会丢失。

查看错误日志

1
2
3
4
5
# 查看错误日志
tail -f /var/log/mysql/error.log

# 查看最近的错误
grep -i error /var/log/mysql/error.log | tail -20

二、慢查询日志(Slow Query Log)

功能说明

慢查询日志记录了执行时间超过指定阈值的 SQL 语句,用于性能分析和优化。通过分析慢查询日志,可以找出需要优化的 SQL 语句。

主要记录内容

  • 执行时间超过 long_query_time 的 SQL 语句
  • 未使用索引的查询(如果开启 log_queries_not_using_indexes
  • 锁等待时间超过 long_query_time 的查询(如果开启 log_slow_admin_statements

配置方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-- 查看慢查询日志是否开启
SHOW VARIABLES LIKE 'slow_query_log';

-- 开启慢查询日志
SET GLOBAL slow_query_log = 'ON';

-- 查看慢查询日志文件位置
SHOW VARIABLES LIKE 'slow_query_log_file';

-- 设置慢查询时间阈值(秒)
SET GLOBAL long_query_time = 2;

-- 记录未使用索引的查询
SET GLOBAL log_queries_not_using_indexes = 'ON';

-- 记录管理语句(如 ALTER TABLE)
SET GLOBAL log_slow_admin_statements = 'ON';
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# my.cnf 配置
[mysqld]
# 开启慢查询日志
slow_query_log = 1

# 慢查询日志文件路径
slow_query_log_file = /var/log/mysql/slow.log

# 慢查询时间阈值(秒)
long_query_time = 2

# 记录未使用索引的查询
log_queries_not_using_indexes = 1

# 记录管理语句
log_slow_admin_statements = 1

# 慢查询日志格式(MySQL 5.7+)
# FILE: 文件格式(默认)
# TABLE: 表格式(记录到 mysql.slow_log 表)
log_output = FILE

实现原理

慢查询日志在 SQL 语句执行完成后,如果执行时间超过阈值,则记录该语句的详细信息。记录内容包括:

  • SQL 语句
  • 执行时间
  • 锁等待时间
  • 返回行数
  • 扫描行数

分析慢查询日志

1
2
3
4
5
6
7
8
9
10
11
# 使用 mysqldumpslow 分析(MySQL 自带工具)
mysqldumpslow /var/log/mysql/slow.log

# 按执行时间排序,显示前 10 条
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log

# 按访问次数排序
mysqldumpslow -s c -t 10 /var/log/mysql/slow.log

# 使用 pt-query-digest 分析(Percona Toolkit)
pt-query-digest /var/log/mysql/slow.log

慢查询日志格式示例

1
2
3
4
5
# Time: 2024-01-15T10:30:45.123456Z
# User@Host: root[root] @ localhost [] Id: 5
# Query_time: 3.456789 Lock_time: 0.000123 Rows_sent: 100 Rows_examined: 1000000
SET timestamp=1705315845;
SELECT * FROM large_table WHERE unindexed_column = 'value';

三、二进制日志(Binary Log / Binlog)

功能说明

二进制日志记录了所有对数据库进行修改的 SQL 语句(DDL 和 DML),但不包括 SELECT 和 SHOW 等不修改数据的语句。Binlog 是 MySQL 主从复制的核心,也用于数据恢复和审计。

主要用途

  1. 主从复制:从库通过读取主库的 Binlog 来同步数据
  2. 数据恢复:通过 Binlog 可以恢复到任意时间点
  3. 数据审计:记录所有数据变更操作

配置方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- 查看 Binlog 是否开启
SHOW VARIABLES LIKE 'log_bin';

-- 查看 Binlog 格式
SHOW VARIABLES LIKE 'binlog_format';

-- 查看当前 Binlog 文件
SHOW BINARY LOGS;

-- 查看当前正在使用的 Binlog 文件
SHOW MASTER STATUS;

-- 查看 Binlog 事件
SHOW BINLOG EVENTS IN 'mysql-bin.000001' FROM 4 LIMIT 10;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# my.cnf 配置
[mysqld]
# 开启 Binlog
log-bin=mysql-bin

# Binlog 文件路径(可选,默认在数据目录)
log-bin=/var/lib/mysql/mysql-bin

# Binlog 格式
# STATEMENT: 记录 SQL 语句(默认,性能好但可能不安全)
# ROW: 记录每行数据的变化(安全但文件大)
# MIXED: 混合模式,自动选择
binlog_format=ROW

# Binlog 过期时间(秒),0 表示不过期
expire_logs_days=7

# 单个 Binlog 文件大小(默认 1GB)
max_binlog_size=1G

# Binlog 缓存大小
binlog_cache_size=1M

# 同步 Binlog 到磁盘的方式
# 0: 由操作系统决定何时同步(性能最好,但可能丢失数据)
# 1: 每次事务提交都同步(最安全,但性能较差)
# N: 每 N 个事务提交同步一次
sync_binlog=1

Binlog 格式详解

1. STATEMENT 格式

记录 SQL 语句本身,文件小,但可能因为函数、触发器等原因导致主从不一致。

1
2
-- Binlog 中记录的内容
UPDATE users SET balance = balance + 100 WHERE id = 1;

2. ROW 格式

记录每行数据的变化,文件大,但能保证主从一致性。

1
2
3
-- Binlog 中记录的内容(伪代码)
UPDATE users SET balance = 200 WHERE id = 1;
-- 实际记录:id=1 的行,balance 从 100 变为 200

3. MIXED 格式

混合模式,对于可能引起不一致的语句使用 ROW 格式,其他使用 STATEMENT 格式。

实现原理

Binlog 由 MySQL 服务器层实现,不依赖存储引擎。写入流程:

flowchart TD
    A["事务执行"] --> B["写入 Binlog 缓存
内存"] B --> C["事务提交"] C --> D{"sync_binlog
配置"} D -->|sync_binlog=1| E["立即刷盘"] D -->|sync_binlog=0| F["由 OS 决定"] D -->|sync_binlog=N| G["每 N 个事务刷盘"] E --> H["写入 Binlog 文件"] F --> H G --> H H --> I{"文件大小
> max_binlog_size?"} I -->|是| J["切换新文件"] I -->|否| K["继续写入"] style A fill:#e1f5ff style B fill:#e8f5e9 style C fill:#fff3e0 style H fill:#f3e5f5 style J fill:#fce4ec

查看和分析 Binlog

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 使用 mysqlbinlog 工具查看
mysqlbinlog /var/lib/mysql/mysql-bin.000001

# 查看指定时间范围的 Binlog
mysqlbinlog --start-datetime="2024-01-15 10:00:00" \
--stop-datetime="2024-01-15 11:00:00" \
/var/lib/mysql/mysql-bin.000001

# 查看指定位置的 Binlog
mysqlbinlog --start-position=4 --stop-position=100 \
/var/lib/mysql/mysql-bin.000001

# 将 Binlog 转换为 SQL 语句
mysqlbinlog /var/lib/mysql/mysql-bin.000001 > binlog.sql

# 使用 Binlog 恢复数据
mysqlbinlog --start-position=4 /var/lib/mysql/mysql-bin.000001 | mysql -u root -p

四、重做日志(Redo Log)

功能说明

Redo Log 是 InnoDB 存储引擎特有的日志,用于保证事务的持久性(Durability)。它记录了事务对数据页的物理修改,用于崩溃恢复。

主要功能

  1. 崩溃恢复:MySQL 重启时,通过 Redo Log 恢复未提交但已写入磁盘的数据
  2. 保证持久性:确保已提交事务的修改不会因为崩溃而丢失
  3. 提高性能:将随机写转换为顺序写

配置方法

1
2
3
4
5
-- 查看 Redo Log 相关配置
SHOW VARIABLES LIKE 'innodb_log%';

-- 查看 Redo Log 状态
SHOW ENGINE INNODB STATUS\G
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# my.cnf 配置
[mysqld]
# Redo Log 文件组数(默认 2)
innodb_log_files_in_group = 2

# 每个 Redo Log 文件大小(默认 48MB)
# 建议设置为缓冲池大小的 25%-50%
innodb_log_file_size = 256M

# Redo Log 缓冲区大小(默认 16MB)
innodb_log_buffer_size = 16M

# Redo Log 刷盘策略
# 0: 每秒刷盘一次(性能最好,但可能丢失 1 秒数据)
# 1: 每次事务提交都刷盘(最安全,但性能较差,默认)
# 2: 每次事务提交写入 OS 缓存,由 OS 决定何时刷盘
innodb_flush_log_at_trx_commit = 1

实现原理

Redo Log 结构

Redo Log 由多个固定大小的文件组成(通常为 2 个),采用循环写入的方式:

graph LR
    A["ib_logfile0
(256MB)"] --> B["ib_logfile1
(256MB)"] B --> A A --> C["写入位置"] B --> D["循环使用"] style A fill:#e1f5ff style B fill:#e8f5e9 style C fill:#fff3e0 style D fill:#f3e5f5

写入流程

flowchart TD
    A["事务执行
修改数据页"] --> B["写入 Redo Log Buffer
内存"] B --> C["事务提交"] C --> D{"innodb_flush_log_at_trx_commit"} D -->|值为 0| E["每秒刷盘一次"] D -->|值为 1| F["每次提交都刷盘"] D -->|值为 2| G["写入 OS 缓存"] E --> H["Redo Log 文件
磁盘"] F --> H G --> H I["后台线程"] --> H I -.->|定期刷盘| B style A fill:#e1f5ff style B fill:#e8f5e9 style C fill:#fff3e0 style H fill:#f3e5f5 style I fill:#fce4ec

WAL 机制

Redo Log 实现了 Write-Ahead Logging(WAL) 机制:

sequenceDiagram
    participant T as 事务
    participant R as Redo Log
    participant D as 数据页
    participant C as 崩溃恢复
    
    Note over T: 修改数据
    T->>R: 1. 先写 Redo Log
(已刷盘) T->>D: 2. 后写数据页
(可能未刷盘) Note over T,C: 如果此时崩溃 C->>R: 读取 Redo Log R->>D: 恢复数据页 Note over C: 数据恢复完成

Redo Log 与 Binlog 的区别

特性 Redo Log Binlog
所属层级 InnoDB 存储引擎 MySQL 服务器层
记录内容 物理日志(数据页的修改) 逻辑日志(SQL 语句或行数据变化)
用途 崩溃恢复、保证持久性 主从复制、数据恢复、审计
文件格式 固定大小,循环写入 追加写入,可配置大小
事务性 支持事务 不支持事务

两阶段提交(2PC)

为了保证 Redo Log 和 Binlog 的一致性,InnoDB 使用两阶段提交:

sequenceDiagram
    participant T as 事务
    participant R as Redo Log
    participant B as Binlog
    
    Note over T: 阶段1: Prepare
    T->>R: 写入 Redo Log
标记为 Prepare 状态 T->>B: 写入 Binlog Note over T: 阶段2: Commit T->>R: 提交事务
标记为 Commit 状态 Note over T,B: 如果阶段2崩溃 alt Binlog 完整 T->>R: 提交事务 else Binlog 不完整 T->>R: 回滚事务 end

五、回滚日志(Undo Log)

功能说明

Undo Log 是 InnoDB 存储引擎特有的日志,用于实现事务的回滚和 MVCC(多版本并发控制)。它记录了事务修改前的数据版本。

主要功能

  1. 事务回滚:回滚未提交事务的修改
  2. MVCC:为读操作提供历史版本数据,实现快照读
  3. 一致性读:保证可重复读隔离级别下的读一致性

配置方法

1
2
3
4
5
6
-- 查看 Undo Log 相关配置
SHOW VARIABLES LIKE 'innodb_undo%';

-- 查看 Undo Log 表空间
SELECT * FROM INFORMATION_SCHEMA.INNODB_TABLESPACES
WHERE SPACE_TYPE = 'Undo';
1
2
3
4
5
6
7
8
9
10
11
12
13
# my.cnf 配置
[mysqld]
# Undo Log 表空间数量(默认 2,MySQL 8.0+ 可配置)
innodb_undo_tablespaces = 2

# 是否自动清理 Undo Log(默认开启)
innodb_undo_log_truncate = ON

# Undo Log 表空间大小阈值(超过此值触发清理)
innodb_max_undo_log_size = 1G

# Undo Log 清理线程数量
innodb_purge_threads = 4

实现原理

Undo Log 结构

Undo Log 存储在 Undo 表空间中,采用段(Segment)的方式管理:

graph TD
    A["Undo Segment"] --> B["Insert Undo Log
INSERT 操作"] A --> C["Update Undo Log
UPDATE/DELETE 操作"] B --> D["记录插入的主键
用于回滚"] C --> E["记录修改前的数据
用于回滚和 MVCC"] style A fill:#e1f5ff style B fill:#e8f5e9 style C fill:#fff3e0 style D fill:#f3e5f5 style E fill:#fce4ec

写入流程

flowchart TD
    A["SQL 操作"] --> B{"操作类型"}
    B -->|INSERT| C["记录插入行的主键值
Insert Undo Log"] B -->|UPDATE| D["记录修改前的完整行数据
Update Undo Log"] B -->|DELETE| E["标记为删除
记录完整行数据
Update Undo Log"] C --> F["写入 Undo Log"] D --> F E --> F F --> G["Undo 表空间"] style A fill:#e1f5ff style C fill:#e8f5e9 style D fill:#fff3e0 style E fill:#f3e5f5 style G fill:#fce4ec

MVCC 实现

Undo Log 通过版本链实现 MVCC:

graph TD
    A["当前版本
最新数据"] -->|roll_ptr 指针| B["历史版本 1
Undo Log"] B -->|roll_ptr 指针| C["历史版本 2
Undo Log"] C -->|roll_ptr 指针| D["历史版本 3
Undo Log"] D -->|...| E["更早版本"] style A fill:#e1f5ff style B fill:#e8f5e9 style C fill:#fff3e0 style D fill:#f3e5f5 style E fill:#fce4ec

读操作通过 Undo Log 构建历史版本,实现快照读。

Undo Log 清理

Undo Log 在以下情况会被清理:

  1. 事务提交后:Insert Undo Log 可以立即清理
  2. 没有活跃事务使用:Update Undo Log 需要等待没有事务使用该版本
  3. Purge 线程:后台线程定期清理不再需要的 Undo Log

六、通用查询日志(General Query Log)

功能说明

通用查询日志记录了所有到达 MySQL 服务器的 SQL 语句,包括 SELECT、INSERT、UPDATE、DELETE 等所有操作。由于记录所有操作,会产生大量日志,通常只在调试时开启。

配置方法

1
2
3
4
5
6
7
8
9
10
11
-- 查看通用查询日志是否开启
SHOW VARIABLES LIKE 'general_log';

-- 开启通用查询日志
SET GLOBAL general_log = 'ON';

-- 查看通用查询日志文件位置
SHOW VARIABLES LIKE 'general_log_file';

-- 查看日志输出方式
SHOW VARIABLES LIKE 'log_output';
1
2
3
4
5
6
7
8
9
10
11
12
13
# my.cnf 配置
[mysqld]
# 开启通用查询日志
general_log = 1

# 通用查询日志文件路径
general_log_file = /var/log/mysql/general.log

# 日志输出方式
# FILE: 输出到文件
# TABLE: 输出到 mysql.general_log 表
# FILE,TABLE: 同时输出到文件和表
log_output = FILE

注意事项

  • 通用查询日志会产生大量 I/O,影响性能
  • 生产环境通常不开启,只在调试时使用
  • 如果开启,需要定期清理或限制日志文件大小

七、中继日志(Relay Log)

功能说明

中继日志是 MySQL 主从复制中,从库(Slave)特有的日志。它存储从主库(Master)读取的 Binlog 事件,然后由从库的 SQL 线程执行这些事件来同步数据。

主要功能

  1. 存储 Binlog 事件:从主库读取的 Binlog 事件先写入 Relay Log
  2. 解耦 IO 和 SQL 线程:IO 线程读取 Binlog,SQL 线程执行 Relay Log
  3. 提高复制性能:避免 IO 线程和 SQL 线程相互等待

配置方法

1
2
3
4
5
6
7
8
9
10
11
12
13
# my.cnf 配置(从库)
[mysqld]
# 中继日志文件路径
relay-log = /var/lib/mysql/relay-bin

# 中继日志索引文件
relay-log-index = /var/lib/mysql/relay-bin.index

# 中继日志自动清理(默认开启)
relay_log_purge = ON

# 中继日志过期时间(秒)
relay_log_recovery = ON

实现原理

主从复制流程

sequenceDiagram
    participant M as 主库 (Master)
    participant B as Binlog
    participant IO as IO 线程
    participant R as Relay Log
    participant SQL as SQL 线程
    participant S as 从库 (Slave)
    
    M->>B: 写入 Binlog
    B->>IO: IO 线程读取 Binlog
    IO->>R: 写入 Relay Log
    R->>SQL: SQL 线程读取 Relay Log
    SQL->>S: 应用数据变更
    
    Note over M,S: 主从复制完成

Relay Log 结构

Relay Log 的结构和 Binlog 类似,采用追加写入的方式:

graph LR
    A["relay-bin.000001"] --> B["relay-bin.000002"]
    B --> C["relay-bin.000003"]
    C --> D["relay-bin.000004"]
    D --> E["..."]
    
    style A fill:#e1f5ff
    style B fill:#e8f5e9
    style C fill:#fff3e0
    style D fill:#f3e5f5
    style E fill:#fce4ec

八、日志对比总结

日志类型 所属层级 主要用途 是否必需 性能影响
错误日志 服务器层 记录错误和警告
慢查询日志 服务器层 性能分析
Binlog 服务器层 主从复制、恢复 主从复制必需
Redo Log InnoDB 崩溃恢复、持久性
Undo Log InnoDB 回滚、MVCC
通用查询日志 服务器层 调试、审计
Relay Log 服务器层 主从复制 从库必需

日志文件位置

1
2
3
4
5
6
7
8
9
10
# 查看所有日志文件位置
mysql> SHOW VARIABLES LIKE '%log%';

# 常见日志文件位置
/var/log/mysql/error.log # 错误日志
/var/log/mysql/slow.log # 慢查询日志
/var/lib/mysql/mysql-bin.000001 # Binlog
/var/lib/mysql/ib_logfile0 # Redo Log
/var/lib/mysql/undo_001 # Undo Log
/var/lib/mysql/relay-bin.000001 # Relay Log

日志管理建议

  1. 定期清理:设置日志过期时间,定期清理旧日志
  2. 监控大小:监控日志文件大小,避免占满磁盘
  3. 性能优化:根据业务需求调整日志级别和格式
  4. 备份重要日志:Binlog 和 Redo Log 对数据恢复至关重要

九、日志相关最佳实践

1. 生产环境配置建议

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[mysqld]
# 错误日志
log-error=/var/log/mysql/error.log
log_error_verbosity=2

# 慢查询日志
slow_query_log=1
slow_query_log_file=/var/log/mysql/slow.log
long_query_time=2
log_queries_not_using_indexes=0

# Binlog
log-bin=mysql-bin
binlog_format=ROW
expire_logs_days=7
sync_binlog=1

# Redo Log
innodb_log_file_size=256M
innodb_flush_log_at_trx_commit=1

# Undo Log
innodb_undo_log_truncate=ON
innodb_max_undo_log_size=1G

2. 日志监控脚本示例

1
2
3
4
5
6
7
8
9
10
#!/bin/bash
# 监控日志文件大小

LOG_DIR="/var/log/mysql"
DATA_DIR="/var/lib/mysql"

echo "=== MySQL 日志文件大小 ==="
du -h $LOG_DIR/*.log 2>/dev/null
du -h $DATA_DIR/mysql-bin.* 2>/dev/null
du -h $DATA_DIR/ib_logfile* 2>/dev/null

3. 日志分析工具

  • mysqldumpslow:分析慢查询日志
  • pt-query-digest:Percona Toolkit 中的日志分析工具
  • mysqlbinlog:查看和分析 Binlog
  • mysql error log:直接查看错误日志

参考文献


文章作者: djaigo
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 djaigo !
评论
  目录