MySQL的三大日志

大家好,我是苏三,又跟大家见面了。

前言

飞机失事靠黑匣子还原真相,MySQL崩溃靠三大日志保障数据安全。

作为一个工作多年的程序员,我见过太多因日志配置不当引发的灾难:数据丢失、主从同步中断、事务回滚失败...

今天,我将用最通俗的方式,带你彻底掌握MySQL三大日志的底层原理,希望对你会有所帮助。

最近准备面试的小伙伴,可以看一下这个宝藏网站(Java突击队):www.susan.net.cn,里面:面试八股文、场景题、面试真题、项目实战、工作内推什么都有

一、引子:一个数据丢失的教训

事故现场:某电商平台数据库服务器宕机后,发现最近2小时订单数据丢失。

问题根源: 错误配置导致redo log刷盘失效:

sql 复制代码
SHOW VARIABLES LIKE 'innodb_flush_log_at_trx_commit';
+--------------------------------+-------+
| Variable_name                  | Value |
+--------------------------------+-------+
| innodb_flush_log_at_trx_commit | 0     |  -- 应设为1
+--------------------------------+-------+

核心结论

  1. 日志系统是MySQL的安全气囊
  2. 不理解日志机制,等于在数据安全上裸奔

二、Redo Log:保证持久性的守护神

2.1 核心作用:崩溃恢复

WAL原则(Write-Ahead Logging)

2.2 物理结构解析

循环写入机制

关键参数

sql 复制代码
-- 查看日志配置
SHOW VARIABLES LIKE 'innodb_log%';
+---------------------------+---------+
| Variable_name             | Value   |
+---------------------------+---------+
| innodb_log_file_size      | 50331648| -- 单个日志文件大小
| innodb_log_files_in_group | 2       | -- 日志文件数量
| innodb_log_buffer_size    | 16777216| -- 缓冲区大小
+---------------------------+---------+

2.3 刷盘策略实战

java 复制代码
// JDBC事务提交示例
Connection conn = DriverManager.getConnection(url, user, pwd);
try {
    conn.setAutoCommit(false);
    Statement stmt = conn.createStatement();
    stmt.executeUpdate("UPDATE account SET balance=balance-100 WHERE id=1");
    stmt.executeUpdate("UPDATE account SET balance=balance+100 WHERE id=2");
    
    // 核心配置:刷盘策略
    conn.setClientInfo("innodb_flush_log_at_trx_commit", "1");
    conn.commit(); // 触发redo log刷盘
} catch (SQLException e) {
    conn.rollback();
}

刷盘策略对比

参数值 安全性 性能 适用场景
0 低(每秒刷) 最高 可丢失数据的缓存
1 最高(实时) 最低 金融交易系统
2 中(OS缓存) 较高 常规业务系统

三、Undo Log:事务回滚的时光机

3.1 MVCC实现原理

多版本控制流程

3.2 回滚操作源码级解析

sql 复制代码
-- 事务回滚示例
START TRANSACTION;
UPDATE users SET name='张三' WHERE id=1; 
-- 在undo log中记录:
-- | 事务ID | 行ID | 旧值 | 回滚指针 |
-- | 101    | 1    | '李四'| 0x7F8A9B|

ROLLBACK; -- 根据undo log恢复数据

3.3 长事务引发的灾难

问题场景

sql 复制代码
-- 查询运行超过60秒的事务
SELECT * FROM information_schema.innodb_trx 
WHERE TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) > 60;

严重后果

  1. Undo Log暴涨占用磁盘空间
  2. 历史版本链过长导致查询性能下降

解决方案

java 复制代码
@Transactional(timeout = 30) // 单位:秒
public void updateOrder(Order order) {
    // 业务逻辑
}

Spring Boot项目可以设置事务超时时间。

最近建了一些工作内推群,各大城市都有,欢迎各位HR和找工作的小伙伴进群交流,群里目前已经收集了不少的工作内推岗位。加苏三的微信:li_su223,备注:掘金+所在城市,即可进群。

四、Binlog:主从复制的桥梁

4.1 三种格式深度对比

格式 特点 数据安全 复制效率
STATEMENT 记录SQL语句
ROW 记录行变化
MIXED 自动切换模式

ROW格式的优势

lua 复制代码
-- 原始SQL
UPDATE users SET status=1 WHERE age>30;

-- ROW格式binlog实际记录
/* 修改前镜像 */
id:1, status:0, age:35
id:2, status:0, age:40
/* 修改后镜像 */
id:1, status:1, age:35
id:2, status:1, age:40

4.2 主从复制全流程剖析

4.3 数据恢复实战

场景 :误删全表数据
恢复步骤

perl 复制代码
# 1. 解析binlog找到删除位置
mysqlbinlog --start-position=763 --stop-position=941 binlog.000001 > recovery.sql

# 2. 提取回滚SQL
grep -i 'DELETE FROM users' recovery.sql

# 3. 生成反向补偿语句
sed 's/DELETE FROM/INSERT INTO/g' recovery.sql > rollback.sql

# 4. 执行恢复
mysql -u root -p < rollback.sql

五、三大日志协同工作图

更新语句执行流程

两阶段提交关键点

  1. redo log prepare 与 binlog 写入的原子性
  2. 崩溃恢复时的决策逻辑:
    • binlog完整:提交事务
    • binlog不完整:回滚事务

六、生产环境优化指南

6.1 参数调优模板

my.cnf 关键配置:

ini 复制代码
[mysqld]
# Redo Log
innodb_log_file_size = 2G        # 建议4个日志文件
innodb_log_files_in_group = 4
innodb_flush_log_at_trx_commit = 1

# Undo Log
innodb_max_undo_log_size = 1G
innodb_undo_log_truncate = ON
innodb_purge_threads = 4

# Binlog
server_id = 1
log_bin = /data/mysql-bin
binlog_format = ROW
binlog_expire_logs_seconds = 604800 # 保留7天
sync_binlog = 1                   # 每次提交刷盘

6.2 监控指标清单

sql 复制代码
-- 关键监控SQL
SELECT
/* Redo Log */
  (SELECT VARIABLE_VALUE 
   FROM performance_schema.global_status 
   WHERE VARIABLE_NAME='Innodb_os_log_written') AS redo_written,
   
/* Undo Log */
  (SELECTSUM(DATA_LENGTH) 
   FROM information_schema.TABLES 
   WHERE TABLE_SCHEMA='mysql'
   AND TABLE_NAME LIKE'undo%') AS undo_size,
   
/* Binlog */
  (SELECT VARIABLE_VALUE 
   FROM performance_schema.global_status 
   WHERE VARIABLE_NAME='Binlog_cache_disk_use') AS binlog_disk_use;

6.3 常见问题解决方案

问题1:redo log文件设置过小导致频繁checkpoint。

现象

sql 复制代码
SHOW GLOBAL STATUS LIKE 'Innodb_log_waits';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| Innodb_log_waits | 542   | -- 值>0表示存在等待
+------------------+-------+

解决

ini 复制代码
# 动态调整(需重启生效)
SET GLOBAL innodb_log_file_size = 2147483648; 

问题2:大事务导致binlog暴涨。

预防方案

ini 复制代码
// 事务拆分示例
public void batchProcess(List<Order> orders) {
    int batchSize = 100; // 每100条一个事务
    for (int i=0; i<orders.size(); i+=batchSize) {
        transactionTemplate.execute(status -> {
            List<Order> subList = orders.subList(i, Math.min(i+batchSize, orders.size()));
            processBatch(subList);
            return null;
        });
    }
}

七、总结

  1. Redo Log是生命线
    • 配置原则:innodb_flush_log_at_trx_commit=1 + 足够大的日志文件
    • 监控重点:Innodb_log_waits 应趋近于0
  2. Undo Log是后悔药
    • 及时清理:开启 innodb_undo_log_truncate
    • 避免长事务:监控 information_schema.innodb_trx
  3. Binlog是复制基石
    • 格式选择:金融级系统必须用ROW格式
    • 同步策略:主从复制时 sync_binlog=1

数据库的可靠性不是偶然发生的,而是通过三大日志的精密协作实现的。

当你下次执行COMMIT时,请记住背后有三个强大的守护者在为你工作:

  1. Redo Log确保你的数据不会丢失
  2. Undo Log保证你的操作可以撤销
  3. Binlog让数据在集群间流动

敬畏日志,就是敬畏数据安全!

最后说一句(求关注,别白嫖我)

如果这篇文章对您有所帮助,或者有所启发的话,帮忙关注一下我的同名公众号:苏三说技术,您的支持是我坚持写作最大的动力。

求一键三连:点赞、转发、在看。

关注公众号:【苏三说技术】,在公众号中回复:进大厂,可以免费获取我最近整理的10万字的面试宝典,好多小伙伴靠这个宝典拿到了多家大厂的offer。

本文收录于我的技术网站:www.susan.net.cn

相关推荐
神奇小汤圆8 小时前
浅析二叉树、B树、B+树和MySQL索引底层原理
后端
文艺理科生8 小时前
Nginx 路径映射深度解析:从本地开发到生产交付的底层哲学
前端·后端·架构
千寻girling8 小时前
主管:”人家 Node 框架都用 Nest.js 了 , 你怎么还在用 Express ?“
前端·后端·面试
南极企鹅8 小时前
springBoot项目有几个端口
java·spring boot·后端
Luke君607978 小时前
Spring Flux方法总结
后端
define95279 小时前
高版本 MySQL 驱动的 DNS 陷阱
后端
忧郁的Mr.Li9 小时前
SpringBoot中实现多数据源配置
java·spring boot·后端
暮色妖娆丶10 小时前
SpringBoot 启动流程源码分析 ~ 它其实不复杂
spring boot·后端·spring
Coder_Boy_10 小时前
Deeplearning4j+ Spring Boot 电商用户复购预测案例中相关概念
java·人工智能·spring boot·后端·spring
Java后端的Ai之路10 小时前
【Spring全家桶】-一文弄懂Spring Cloud Gateway
java·后端·spring cloud·gateway