第31章 MySQL 日志系统
本章目标
- 全面掌握 MySQL 的五大日志系统及其用途
- 理解每种日志的配置、查看、分析和管理方法
- 掌握慢查询日志的捕获和分析,能够使用 mysqldumpslow 和 pt-query-digest
- 深入理解 Redo Log、Undo Log 和 Binary Log 三者的区别与协作关系
- 掌握 InnoDB 的 WAL(Write-Ahead Logging)机制和崩溃恢复原理
- 理解各日志在生产环境中的最佳配置实践
前置知识
- 了解 MySQL 的基本架构(连接层、服务层、存储引擎层)
- 理解事务的 ACID 特性
- 了解 InnoDB 存储引擎的基本概念
- 具有 MySQL 配置文件(my.cnf / my.ini)的基本操作经验
31.1 错误日志 (Error Log)
31.1.1 是什么
错误日志记录了 MySQL 服务器的启动/关闭事件、运行中遇到的错误和警告、以及重要的状态变化。它是排查 MySQL 问题的第一个信息来源。
31.1.2 配置与查看
-- 查看错误日志位置
SHOW VARIABLES LIKE 'log_error';
-- 典型输出:
-- +---------------+-----------------------------------+
-- | Variable_name | Value |
-- +---------------+-----------------------------------+
-- | log_error | /var/log/mysql/error.log |
-- +---------------+-----------------------------------+
-- 查看日志详细级别
SHOW VARIABLES LIKE 'log_error_verbosity';
-- 详细级别说明:
-- 1 = 仅错误(ERROR)
-- 2 = 错误 + 警告(ERROR + WARNING)
-- 3 = 错误 + 警告 + 信息(ERROR + WARNING + NOTE)—— MySQL 8.0 默认值# my.cnf / my.ini 配置
[mysqld]
log_error = /var/log/mysql/error.log # 错误日志文件路径
log_error_verbosity = 3 # 日志详细级别(1/2/3)31.1.3 错误日志包含的内容
### 启动信息
2024-01-15T08:00:00.123456Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.35) starting as process 1234
### InnoDB 初始化
2024-01-15T08:00:01.234567Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
2024-01-15T08:00:03.345678Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
### 端口监听
2024-01-15T08:00:04.456789Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.35'. socket: '/var/run/mysqld/mysqld.sock'. port: 3306.
### 连接异常
2024-01-15T09:30:00.567890Z 100 [Warning] [MY-010068] [Server] Aborted connection 100 to db: 'mydb' user: 'app_user' host: '192.168.1.100' (Got timeout reading communication packets)
### 复制错误
2024-01-15T10:00:00.678901Z 50 [ERROR] [MY-010584] [Repl] Slave SQL for channel '': Error 'Duplicate entry '123' for key 'PRIMARY'' on query. Default database: 'mydb'. Query: 'INSERT INTO users VALUES (123, ...)', Error_code: MY-001062
### 崩溃恢复
2024-01-15T10:30:00.789012Z 0 [System] [MY-013722] [InnoDB] Database was not shutdown normally!
2024-01-15T10:30:00.890123Z 0 [System] [MY-013723] [InnoDB] Starting crash recovery.
2024-01-15T10:30:05.901234Z 0 [System] [MY-013724] [InnoDB] End of crash recovery.31.1.4 错误日志的日常使用
# 监控错误日志(实时跟踪)
tail -f /var/log/mysql/error.log
# 查找最近的错误
grep -i "error" /var/log/mysql/error.log | tail -20
# 查找连接异常
grep "Aborted connection" /var/log/mysql/error.log | wc -l
# 按日期筛选日志
grep "2024-01-15" /var/log/mysql/error.log
# 搜索特定错误码
grep "MY-001062" /var/log/mysql/error.log # 1062 = 重复键错误
# 日志轮转(推荐使用 logrotate)
# /etc/logrotate.d/mysql
# /var/log/mysql/error.log {
# daily
# rotate 30
# missingok
# compress
# postrotate
# mysqladmin flush-logs
# endscript
# }31.2 通用查询日志 (General Query Log)
31.2.1 是什么
通用查询日志记录了每一个客户端连接、断开连接和每一条执行的 SQL 语句。它是最详细的日志,但由于记录量巨大,通常仅在调试和审计时临时启用。
31.2.2 配置
-- 查看通用日志状态
SHOW VARIABLES LIKE 'general_log%';
-- +------------------+----------------------------------+
-- | Variable_name | Value |
-- +------------------+----------------------------------+
-- | general_log | OFF |
-- | general_log_file | /var/lib/mysql/hostname.log |
-- +------------------+----------------------------------+
-- 临时启用(动态修改,重启后失效)
SET GLOBAL general_log = 'ON';
SET GLOBAL general_log = 'OFF';
-- 日志输出到表(而非文件),方便 SQL 查询
SET GLOBAL log_output = 'TABLE';
SET GLOBAL general_log = 'ON';
-- 查询日志表
SELECT * FROM mysql.general_log ORDER BY event_time DESC LIMIT 20;# my.cnf 永久配置
[mysqld]
general_log = 0 # 0=OFF, 1=ON(生产环境强烈建议 OFF)
general_log_file = /var/log/mysql/general.log
log_output = FILE # FILE, TABLE, 或 FILE,TABLE31.2.3 警告
在生产环境长期开启通用查询日志会严重降低性能(10-30% 甚至更多),因为每一条 SQL 都需要写入日志。仅在排查特定问题时临时开启,排查完毕后立即关闭。
31.3 慢查询日志 (Slow Query Log)
31.3.1 是什么
慢查询日志记录了执行时间超过 long_query_time 阈值的 SQL 语句。它是性能优化的首要入口——找到执行最慢的查询,然后使用 EXPLAIN 分析并优化。
31.3.2 配置
-- 查看慢查询日志配置
SHOW VARIABLES LIKE 'slow_query%';
SHOW VARIABLES LIKE 'long_query_time';
-- +-----------------------------+----------------------------------+
-- | Variable_name | Value |
-- +-----------------------------+----------------------------------+
-- | slow_query_log | OFF |
-- | slow_query_log_file | /var/lib/mysql/hostname-slow.log |
-- | long_query_time | 10.000000 |
-- +-----------------------------+----------------------------------+# my.cnf 推荐配置
[mysqld]
# === 慢查询日志 ===
slow_query_log = 1 # 开启慢查询日志
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2 # 超过 2 秒的查询
log_queries_not_using_indexes = 1 # 同时记录不使用索引的查询
log_slow_admin_statements = 1 # 同时记录慢的 DDL 语句
min_examined_row_limit = 1000 # 至少扫描 1000 行的查询才记录
log_slow_extra = ON # MySQL 8.0.14+: 额外信息(字节数等)
log_output = FILE # 输出到文件(也可以 TABLE)31.3.3 慢查询日志格式
# Time: 2024-01-15T10:30:45.123456Z
# User@Host: app_user[app_user] @ 192.168.1.100 [192.168.1.100] Id: 42
# Query_time: 5.234567 Lock_time: 0.001234 Rows_sent: 100 Rows_examined: 500000
# Bytes_sent: 12345 (MySQL 8.0.14+ with log_slow_extra)
SET timestamp=1705314645;
SELECT o.*, u.name, u.email
FROM orders o
JOIN users u ON o.user_id = u.id
WHERE o.status = 'shipped'
ORDER BY o.created_at DESC
LIMIT 100;字段说明:
- Query_time:查询执行的总时间(秒)
- Lock_time:等待锁的时间(秒)—— 如果这个值很高,说明存在锁竞争
- Rows_sent:返回给客户端的行数
- Rows_examined:实际扫描的行数 —— Rows_examined >> Rows_sent 说明索引有问题
- Bytes_sent:发送的数据量
31.3.4 慢查询日志分析工具
1. mysqldumpslow(MySQL 自带)
# 按查询时间排序(最慢的 10 条)
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
# 按出现次数排序(最多的 10 条)
mysqldumpslow -s c -t 10 /var/log/mysql/slow.log
# 按返回行数排序
mysqldumpslow -s r -t 10 /var/log/mysql/slow.log
# 按锁等待时间排序
mysqldumpslow -s l -t 10 /var/log/mysql/slow.log
# 包含具体值的查询(不聚合)
mysqldumpslow -a -s t -t 5 /var/log/mysql/slow.log
# 按模式分组(默认行为)
mysqldumpslow -s t -t 5 /var/log/mysql/slow.log
# 输出:
# Count: 50 Time=3.45s (172s) Lock=0.00s (0s) Rows=1.0 (50)
# SELECT * FROM orders WHERE user_id=N AND status='S'2. pt-query-digest(Percona Toolkit)
pt-query-digest 远比 mysqldumpslow 强大,是生产环境分析慢查询的首选工具:
# 分析慢查询日志
pt-query-digest /var/log/mysql/slow.log > slow_report.txt
# 分析最近 12 小时的慢查询
pt-query-digest --since='12h' /var/log/mysql/slow.log
# 分析到指定时间为止
pt-query-digest --until='2024-01-15 12:00:00' /var/log/mysql/slow.log
# 分析指定数据库的查询
pt-query-digest --filter '$event->{db} eq "mydb"' /var/log/mysql/slow.log
# 输出报告包含:
# - 总体统计(查询数、唯一模式数、执行时间分布)
# - 按查询时间排序的 TOP 查询
# - 每个查询的详细分析:
# - 执行次数、总时间、平均/中位数/95%/99% 时间
# - 执行时间分布图
# - EXPLAIN 计划
# - 优化建议
# - 按数据库、用户、主机统计
# 分析 processlist 快照
pt-query-digest --processlist h=localhost,u=root,p=password --interval 1 --iterations 60
# 分析 tcpdump 抓取的流量
# tcpdump -i eth0 port 3306 -s 65535 -w mysql.pcap
# pt-query-digest --type tcpdump mysql.pcap31.3.5 慢查询日志到表
-- 将慢查询日志输出到 mysql.slow_log 表
SET GLOBAL log_output = 'TABLE';
-- 查询慢查询日志表
SELECT
start_time,
user_host,
query_time,
lock_time,
rows_sent,
rows_examined,
CONVERT(sql_text USING utf8mb4) AS sql_text
FROM mysql.slow_log
ORDER BY query_time DESC
LIMIT 20;
-- 统计最慢的查询类型
SELECT
LEFT(CONVERT(sql_text USING utf8mb4), 100) AS query_pattern,
COUNT(*) AS count,
AVG(query_time) AS avg_time,
MAX(query_time) AS max_time
FROM mysql.slow_log
WHERE start_time >= DATE_SUB(NOW(), INTERVAL 1 DAY)
GROUP BY query_pattern
ORDER BY avg_time DESC
LIMIT 20;31.4 二进制日志 (Binary Log / Binlog)
31.4.1 是什么
二进制日志记录了**所有对数据库数据产生更改的 SQL 语句或行变更 **。它的三个主要用途:
- 复制(Replication):从库通过读取主库的 binlog 来复制数据
- Point-in-Time Recovery(PITR):恢复全量备份后通过 binlog 恢复到指定时间点
- 审计:追踪谁在什么时间做了什么数据变更(需配合其他审核工具)
31.4.2 三种 binlog 格式
-- 查看当前 binlog 格式
SHOW VARIABLES LIKE 'binlog_format';1. STATEMENT(语句模式)
记录 SQL 语句原文。最小,但非确定性函数(NOW()、UUID()、RAND())会导致主从数据不一致。
-- 假设执行:
INSERT INTO orders (user_id, created_at) VALUES (1, NOW());
-- STATEMENT 模式下 binlog 记录:
-- INSERT INTO orders (user_id, created_at) VALUES (1, NOW());
-- 问题:主从执行 NOW() 的时间不同 → 数据不一致!2. ROW(行模式)—— 推荐
记录每一行数据变更的前后镜像。数据一致性最好,但日志量最大。
-- ROW 模式下 binlog 记录(伪代码展示):
-- ### INSERT INTO `mydb`.`orders`
-- ### SET
-- ### @1=1 (user_id)
-- ### @2='2024-01-15 10:00:00' (created_at,已确定的值!)
-- 问题消失:从库直接复制确切值,不执行 NOW()3. MIXED(混合模式)
大部分语句使用 STATEMENT,当 MySQL 判断语句可能产生不一致时自动切换为 ROW。
# 推荐配置
[mysqld]
log_bin = /var/log/mysql/binlog # 开启 binlog,指定文件路径前缀
binlog_format = ROW # 使用 ROW 格式
binlog_expire_logs_seconds = 604800 # 7 天后自动清理(替代旧版 expire_logs_days)
max_binlog_size = 1073741824 # 1GB 后自动切换新文件
binlog_row_image = FULL # FULL(完整行)/ MINIMAL(仅变更列)/ NOBLOB
sync_binlog = 1 # 每次事务提交后同步 binlog 到磁盘(1=最安全)31.4.3 管理和查看
-- 查看所有 binlog 文件
SHOW BINARY LOGS;
-- 查看当前 binlog 位置
SHOW MASTER STATUS;
-- 查看 binlog 事件
SHOW BINLOG EVENTS IN 'binlog.000001' LIMIT 20;
-- 查看指定位置的 binlog 事件
SHOW BINLOG EVENTS IN 'binlog.000001' FROM 1234 LIMIT 10;
-- 手动刷新日志(关闭当前文件,开启新文件)
FLUSH LOGS;
-- 或
FLUSH BINARY LOGS;
-- 清理旧 binlog
PURGE BINARY LOGS TO 'binlog.000010'; -- 删除之前的所有日志
PURGE BINARY LOGS BEFORE '2024-06-01'; -- 删除指定日期之前的日志
-- 重置(删除所有 binlog,危险!仅测试环境使用)
RESET MASTER;31.5 Redo Log(重做日志 / InnoDB)
31.5.1 是什么
Redo Log 是 InnoDB 存储引擎独有的日志,记录了对数据页的物理修改。它保证事务的持久性(Durability) —— 即使 MySQL 崩溃,已提交的事务也不会丢失。
核心机制是 WAL(Write-Ahead Logging,预写日志):
修改数据页之前,先将变更记录写入 Redo Log(顺序写,很快)。即使数据页还没来得及写入磁盘,崩溃后也可以通过 Redo Log 重放恢复。
31.5.2 工作原理
事务提交流程:
1. 修改 Buffer Pool 中的数据页(在内存中)
2. 将数据页的变更记录写入 Redo Log Buffer(内存)
3. COMMIT 时:将 Redo Log Buffer 刷新到磁盘的 Redo Log 文件
4. 此时事务被认为已提交(持久化保证)
5. 后续某个时机:将 Buffer Pool 中的脏页刷新到磁盘的数据文件
(Checkpoint 机制,比步骤3晚得多)
崩溃恢复:
1. MySQL 启动时发现 Redo Log 中有已提交但数据页未落盘的事务
2. 重放 Redo Log,将数据页恢复到最新状态
3. 回滚未提交的事务
4. 数据库恢复到一致状态31.5.3 LSN(Log Sequence Number)
LSN 是 Redo Log 中的单调递增序列号,用于追踪日志位置:
-- 查看当前 LSN
SHOW ENGINE INNODB STATUS\G
-- 在输出中查找:
-- Log sequence number 1234567890
-- Log flushed up to 1234567890
-- Pages flushed up to 1234567800
-- Last checkpoint at 1234567000
-- 解释:
-- Log sequence number:当前日志位置(最新产生的 LSN)
-- Log flushed up to:已刷新到磁盘的 LSN
-- Pages flushed up to:数据页已刷新到磁盘的 LSN
-- Last checkpoint at:最近一次 Checkpoint 的 LSN
-- Checkpoint 之前的 Redo Log 空间可以被安全覆盖31.5.4 配置
[mysqld]
# Redo Log 文件大小(每个文件的大小,单位:字节)
innodb_log_file_size = 1073741824 # 1GB(生产环境建议 1-4GB)
# Redo Log 文件组中的文件数量
innodb_log_files_in_group = 2 # 默认 2
# Redo Log 总大小 = innodb_log_file_size × innodb_log_files_in_group
# 配置建议:
# - 文件越大 → Checkpoint 频率越低 → 写性能越好 → 崩溃恢复时间越长
# - 文件越小 → Checkpoint 频繁 → 写性能下降 → 崩溃恢复快
# - 生产环境典型值:1-4 GB × 2 = 2-8 GB 总 Redo Log 空间31.6 Undo Log(回滚日志 / InnoDB)
31.6.1 是什么
Undo Log 记录了数据修改前的"旧版本"。它有两大用途:
- 事务回滚(ROLLBACK):撤销未提交事务的修改
- MVCC(多版本并发控制):为其他事务提供一致性快照读
31.6.2 与 Redo Log 的关系
Redo Log Undo Log
+-------------------------------------------------------+
| 记录内容 | 物理修改(怎么改) | 旧版本数据(改了什么) |
| 写入方式 | 顺序写(追加) | 随机写(回滚段) |
| 保护对象 | 已提交事务不丢失 | 未提交事务可回滚 |
| 方向 | 前滚(重做) | 回滚(撤销) |
| 清理方式 | Checkpoint 后覆盖 | Purge 线程清理 |
| 存储位置 | ib_logfile0/1 | undo tablespace |
+-------------------------------------------------------+示例:UPDATE users SET balance = balance - 100 WHERE id = 1;
Redo Log 记录:
"在 page 123, offset 456 处,将值从 1000 改为 900"
(物理级别的页修改指令)
Undo Log 记录:
"balance 的旧值是 1000"
(逻辑级别的数据前像)
如果 ROLLBACK:
→ 使用 Undo Log 将 balance 恢复为 1000
→ Redo Log 也记录了这个回滚操作(保证 crash safe)
如果另一个事务在 UPDATE 前读取:
→ 通过 Undo Log 构建历史版本
→ 读到 balance = 1000(快照读)31.6.3 Undo 表空间配置
[mysqld]
# Undo 表空间数量(MySQL 8.0 默认 2 个,不能更改已有表空间数量后减少)
innodb_undo_tablespaces = 2
# Undo 表空间文件路径(默认在数据目录下的 undo_001, undo_002)
innodb_undo_directory = /var/lib/mysql/31.6.4 Undo 的两种段类型
1. INSERT Undo Segment(插入撤销段)
- 仅 INSERT 语句使用
- 事务提交后立即可丢弃(因为新插入的行对其他事务不可见)
2. UPDATE Undo Segment(更新撤销段)
- UPDATE 和 DELETE 语句使用
- 事务提交后不能立即丢弃!
- 原因:其他事务可能正在读取旧版本(MVCC 快照读)
- 由后台 Purge 线程在确定没有事务需要旧版本后清理
- 长事务会导致 Undo Log 膨胀(这就是为什么需要避免长事务!)31.7 SHOW ENGINE INNODB STATUS
这是 InnoDB 引擎的"仪表盘",提供了大量运行时信息:
SHOW ENGINE INNODB STATUS\G输出包含的关键部分:
=====================================
2024-01-15 10:30:00 0x7f8a1c0b2700 INNODB MONITOR OUTPUT
=====================================
--- BACKGROUND THREAD ---
# 后台线程状态
--- SEMAPHORES ---
# 信号量等待(互斥锁/读写锁竞争)
--- LATEST DETECTED DEADLOCK ---
# 最近检测到的死锁详情
--- TRANSACTIONS ---
# 活跃事务列表,锁等待信息
--- FILE I/O ---
# 文件 I/O 线程统计
--- INSERT BUFFER AND ADAPTIVE HASH INDEX ---
# 插入缓冲和自适应哈希索引状态
--- LOG ---
# Redo Log 统计(LSN、Checkpoint 等)
--- BUFFER POOL AND MEMORY ---
# Buffer Pool 使用率、命中率、脏页比例
--- ROW OPERATIONS ---
# 行操作统计(读取、插入、更新、删除行数)31.8 五种日志总结对比
+------------------+---------------+------------------------+---------------------+
| 日志类型 | 存储引擎 | 主要用途 | 关键配置 |
+------------------+---------------+------------------------+---------------------+
| Error Log | Server 层 | 调试、故障排查 | log_error |
| General Query Log| Server 层 | 调试、临时审计 | general_log |
| Slow Query Log | Server 层 | 性能优化入口 | long_query_time |
| Binary Log | Server 层 | 复制、PITR | binlog_format=ROW |
| Redo Log | InnoDB (引擎) | 崩溃恢复(持久性) | innodb_log_file_size |
| Undo Log | InnoDB (引擎) | 回滚 + MVCC | innodb_undo_* |
+------------------+---------------+------------------------+---------------------+常见错误
错误 1:在生产环境长期开启通用查询日志
问题:为了排查偶尔出现的慢查询,开启了 general_log,
但忘记关闭,几天后发现服务器负载异常升高。
症状:磁盘 I/O 飙升,写线程阻塞,大量查询排队。
解决:
SET GLOBAL general_log = 'OFF'; -- 立即关闭
-- 改用慢查询日志 + pt-query-digest 定位慢查询错误 2:innodb_log_file_size 设置过小
问题:在高并发写入场景(1000+ TPS)下使用默认的 48MB Redo Log,
导致 Checkpoint 过于频繁,磁盘 I/O 成为瓶颈。
症状:
- SHOW ENGINE INNODB STATUS 中 "pending log writes" 高
- 写入吞吐量远低于磁盘能力
- innodb_log_waits 状态变量持续增长
解决:
-- 增大 Redo Log 大小(需要重启 MySQL)
innodb_log_file_size = 2147483648 # 2GB
-- 验证效果
SHOW STATUS LIKE 'Innodb_log_waits';
-- 理想值为 0错误 3:binlog 和 Redo Log 的混淆
常见误解:
"binlog 已经记录了所有变更,为什么还需要 Redo Log?"
解释:
binlog(Server 层):记录逻辑 SQL,用于复制和 PITR
Redo Log(InnoDB 层):记录物理页修改,用于崩溃恢复
binlog 不能替代 Redo Log,因为:
1. binlog 是逻辑的(SQL 或行变更),无法用于页级别的恢复
2. 崩溃时刻,内存中已修改但未写入 binlog 的数据需要 Redo Log 恢复
3. 两者记录的内容和级别完全不同错误 4:忽略慢查询日志中的 "Rows_examined"
问题:只关注 Query_time(查询时间),忽略了 Rows_examined 远大于 Rows_sent 的情况。
分析:
Rows_examined = 500000, Rows_sent = 100 → 扫描 5000 行返回 1 行
这说明索引设计有问题或者查询没有使用合适的索引
解决:
使用 EXPLAIN 分析该查询,通常可以通过添加索引将 Rows_examined 降低几个数量级错误 5:Undo Log 膨胀导致磁盘空间不足
问题:磁盘空间告警,发现 undo tablespace 文件异常大。
原因:
1. 有长时间未提交的事务(可能是应用 bug 导致的"悬挂"事务)
2. Purge 线程跟不上(高并发 DELETE/UPDATE)
排查:
SELECT trx_id, trx_state, trx_started,
TIMESTAMPDIFF(SECOND, trx_started, NOW()) AS seconds_running,
trx_rows_modified
FROM information_schema.INNODB_TRX
ORDER BY trx_started;
解决:
- 找到并终止长事务
- 检查 innodb_purge_threads 配置
- 重建 undo tablespace(高级操作)本章练习
练习 1:日志配置实践
在新安装的 MySQL 实例上完成以下配置:
- 配置错误日志到独立目录
- 开启慢查询日志,设置阈值为 1 秒
- 配置 binlog 为 ROW 格式,设置 7 天自动清理
- 验证所有配置已生效(使用 SHOW VARIABLES)
- 写入配置文件而非动态设置,确保重启后保留
练习 2:慢查询日志分析
- 创建一个大表(100 万行以上),故意执行几个慢查询
- 启用慢查询日志,捕获这些查询
- 使用 mysqldumpslow 分析慢查询日志,找出 TOP 5
- 使用 pt-query-digest 生成详细报告
- 对比两个工具的分析结果差异
- 针对最慢的查询,给出优化方案并实施
练习 3:Redo Log 大小对性能的影响
- 在默认 Redo Log 大小(48MB)下,用 sysbench 执行写入压力测试,记录 TPS
- 将 Redo Log 增大到 1GB,重复测试
- 将 Redo Log 增大到 4GB,重复测试
- 分析 innodb_log_waits 状态变量的变化
- 解释 TPS 提升的原因(Checkpoint 频率与 Redo Log 大小的关系)
练习 4:Binlog 格式对比
- 创建一个包含 UUID() 和 NOW() 调用的测试场景
- 分别在 STATEMENT、ROW、MIXED 三种格式下执行相同操作
- 使用 mysqlbinlog 查看三种格式下的日志内容差异
- 对比日志文件大小
- 分析为什么 ROW 格式能保证数据一致性
练习 5:崩溃恢复模拟(重要)
- 开启一个事务,INSERT 数据但不提交
- 在另一个会话中查看该事务对数据的可见性(MVCC)
- 使用
kill -9模拟 MySQL 崩溃 - 重启 MySQL,观察错误日志中的崩溃恢复过程
- 验证:未提交的事务被回滚,数据一致性被保持
练习 6:综合日志监控脚本
编写一个监控脚本(Shell/Python),实现:
- 每小时检查慢查询日志是否有新的 TOP 10 慢查询
- 检查错误日志中的 ERROR 级别信息并告警
- 检查 binlog 磁盘空间使用率
- 检查 Undo Log 膨胀情况(SHOW ENGINE INNODB STATUS)
- 生成每日日志健康报告并发送邮件