learning_notes

学习笔记

View project on GitHub

日志

详细分析MySQL事务日志(redo log和undo log)

InnoDB并发如此高,原因竟然在这?

redo 和 undo

为了提高系统性能,减少随机I/O次数,每个事务记录的临时账

事务执行的阶段
  • 修改数据前,写undo log,记录旧值,用于回滚和MVCC。
  • 修改内存中的数据页。
  • 执行事务,并写redo log到log buffer
  • 提交事务,如果innodb_flush_log_at_trx_commit=1,则将redo log写到log file,并刷新落盘,确保持久性。

redo log

  • 解决数据页随机写性能问题,保证事务持久性和崩溃恢复。
  • 数据前滚操作,保存在文件ib_logfile0,循环写入,将checkPoint点推进,数据刷盘
  • redo log buffer是全局共享
mysql> show global variables like "%innodb_log%";
+-----------------------------+----------------------+
| Variable_name               | Value                |
+-----------------------------+----------------------+
| innodb_log_buffer_size      | 8388608              | #默认 8M
| innodb_log_file_size        | 134217728            | #默认 1G
| innodb_log_files_in_group   | 2                    | #文件个数2
| innodb_log_group_home_dir   | /usr/local/mysql/var |
| innodb_flush_log_at_trx_commit | 1                 | #日志何时刷盘 0:只更新buffer 1:fsync刷盘 2:write(page cache)
+-----------------------------+----------------------+
redo log和change buffer

详细介绍

  • change buffer:更新数据缓存起来,不必每次访问磁盘,解决的是随机读磁盘的io消耗,如果修改的是唯一索引,不使用change buffer
  • redo log:解决的是随机写磁盘的io消耗
  • merge: 将change buffer的操作应用到数据页的过程称为 merge。除了访问数据页会触发 merge 外;系统后台有线程会定期 merge;数据库正常关闭的过程中也会触发 merge 操作
redo log的写入机制

除了后台每秒一次的轮询操作外,还有2种场景会让一个没有提交的事务redo log写入到磁盘

  1. redo log buffer 占用的空间即将达到一半,后台线程会主动write,不fsync
  2. 并行事务提交的时候,顺带write

undo log

  • 用来回滚事务,保证原子性的。 数据回滚操作,也叫回滚段,每个回滚段中有1024个undo log segment,默认保存在共享表空间ibdata1,如果设置innodb_file_per_table,将放在每个表的.ibd文件中
# 默认配置
mysql> show global variables like "%undo%";
+--------------------------+------------+
| Variable_name            | Value      |
+--------------------------+------------+
| innodb_max_undo_log_size | 1073741824 |
| innodb_undo_directory    | ./         |
| innodb_undo_log_truncate | OFF        |
| innodb_undo_logs         | 128        |
| innodb_undo_tablespaces  | 0          |
+--------------------------+------------+

binlog

详细介绍mysqlbinlog

binlog写入机制

一个事务的binlog,不能拆开,系统为每个mysql线程分配一片内存 binlog cache,超过限制就暂存到磁盘,由参数binlog_cache_size=32768设置 写入顺序: binlog cache->write(page cache)->fsync(磁盘)

#每次提交事务,不同参数影响
sync_binlog=0 #只写write,不fsync
sync_binlog=1 #fsync
sync_binlog=N(N>1) #每次事务都write,但累计N个事务才fsync
binlog_group_commit_sync_delay=0 #binlog 延迟组提交
binlog_group_commit_sync_no_delay_count=0 #binlog 达到多少数量
cash-safe保证

redo log 和binlog 基于二阶段提交协议

#1. 预处理阶段
redo log prepare(write)->fsync
binlog (write)->fsync
#2. 提交
redo log commit
checkpoint(检查点)

checkpoint是为了定期将db buffer的内容刷新到data file。当遇到内存不足、db buffer已满等情况时,需要将db buffer中的内容/部分内容(特别是脏数据)转储到data file中。在转储时,会记录checkpoint发生的”时刻“。 在故障恢复时候,只需要redo/undo最近的一次checkpoint之后的操作

根据binlog主从同步过程

性能损耗:1%

  1. master开启bin-log功能,日志文件用于记录数据库的读写增删,开启I/O线程
  2. slave开启I/O线程,SQL线程
  3. slave通过I/O线程连接master,请求bin-log,position之后的内容
  4. master收到请求,返给slave数据
  5. slave收到数据,将bin-log写入relay-log中继日志
  6. 开启SQL线程,执行relay-log中的日志
主从复制延迟

主从复制延迟

  • 架构:
    • 从库数量(3-5),如果过多,复制延迟就高。
    • 5.7之后的版本采用多线程复制(一个组提交的事务都是可以并行回放 ),写并发大,来不及传送到从节点。
    • 增加cache层,降低主从库压力。
  • 硬件:
    • 如果从节点硬件不好,升级配置
  • 代码:
    • insert 和 update后sleep几秒(小系统)
    • 不要写慢sql

崩溃处理

  • 恢复的时候可能需要用undo log来回滚未提交的事务。
  • 用redo log来重做已提交但未写入数据文件的操作。

1. 核心对比

| ​日志​ | ​层级​ | ​类型​ | ​主要作用​ | ​持久化方式​ | |———-|—————-|————|—————————-|———————-| | binlog | Server 层 | 逻辑日志 | 主从复制、数据归档与恢复 | 事务提交后异步写入 | | redolog | InnoDB 引擎层 | 物理日志 | 崩溃恢复、保证事务持久性 | 事务提交时强制刷盘 | | undolog | InnoDB 引擎层 | 逻辑日志 | 事务回滚、MVCC 多版本控制 | 通过 redolog 持久化 |


2. 核心作用

binlog

  • 数据归档:记录所有数据变更(DML/DDL)。
  • 主从复制:从库通过重放 binlog 同步数据。
  • 时间点恢复:结合全量备份恢复任意时间点数据。

redolog

  • 崩溃恢复:重启后通过物理日志重放恢复脏页。
  • WAL 机制:先写日志后写数据页,提升写入性能。
  • 持久性保证:事务提交时强制刷盘(innodb_flush_log_at_trx_commit=1)。

undolog

  • 事务回滚:回滚未提交事务,保证原子性。
  • MVCC 支持:提供多版本数据,实现非阻塞读。
  • 旧版本清理:由后台线程 Purge 清理不再需要的旧版本。