MySQL有哪些日志?

MySQL主要有三种日志:undo log、redo log、binlog。前两种是InnoDB特有的,binlog是MySQL的Server层中的。

Buffer Pool

buffer pool是MySQL的缓冲池,里面存储了数据页、索引页、undo页等(与数据库不一致的即为脏页)。对数据库做的操作都会先在buffer pool中执行,后配合redo log持久化到磁盘。

undo log

事务回滚

undo log是回滚日志 ,用于保证事务原子性。在事务执行过程中会记录undo log日志(这里是先记录在buffer pool的undo页中,生成undo log,需要记录对应的redo log),若事务需要回滚,则根据undo log执行与原来相反的操作。

MVCC

我们知道数据库中的一条记录中包含了两个隐藏列:trx_id(事务ID)和roll_pointer(版本指针),undo log记录中也是如此,通过版本指针把记录的旧值连成链表(数据页中的数据就是最新版本),通过版本指针查找记录的旧版本,使用trx_id和Read View判断事务可见性。Read View是什么?

Read View : 快照,在可重复读级别下,每一个事务开始都会生成一个Read View,保证查看的数据一致。

重要字段:

  1. creator_trx_id:创建这个快照的事务ID
  2. m_ids:存储的是当前时刻活跃的事务ID(活跃事务指的是已已启动但未提交的事务)
  3. min_trx_id:活跃事务ID中的最小值
  4. max_trx_id:下一个事务分配的trx_id

如何判断事务可见性?

通过比较记录中的trx_id:

  • trx_id < min_trx_id:代表修改记录的事务早就提交,可见
  • trx_id >= max_trx_id:代表修改记录的事务在当前时刻还没启动,不可见
  • 分两种情况:
    • trx_id m_ids中:事务未提交,不可见
    • trx_id不在 m_ids中:事务已提交,不可见

通过比较trx_id来控制并发事务,这就是MVCC(多版本并发控制)。

redo log

redo log是重做日志 ,使得MySQL具有crash-safe (崩溃恢复)能力,保证了事务的持久性

首先,redo log是一个循环文件组,写入为循环写。通过以下两个参数设置文件数量和文件大小:

innodb_log_files_in_group
innodb_log_file_size

事务执行时的操作会被写入redo log buffer中,记录的字段主要有:操作类型、修改的数据页号、修改数据的页内偏移量、修改的字段值。

write pos指向当前记录的位置,checkpoint指向当前要擦除的位置。

当write pos追上checkpoint时,说明redo log文件满了,这时不能再进行新的更新操作了,更新操作的SQL将被堵塞。此时会停下来把buffer pool中的脏页刷盘,让checkpoint后推,才可以进行操作。

刷盘
  1. 写入方式:redo log文件是顺序写(性能好),而数据页是随机写。
  2. 刷盘时机:
    1. 数据库正常关闭
    2. InnoDB会有一个后台线程每隔一秒将redo log buffer持久化到磁盘
    3. 事务提交时(控制参数:innodb_flush_log_at_trx_commit

innodb_flush_log_at_trx_commit参数

  • 参数为0:留在redo log buffer中,不刷新到磁盘(可能会丢失上1秒的所有数据)。
  • 参数为1:直接刷新到磁盘(fsync)。
  • 参数为2:写入redo log文件(操作系统中的Page Cache)(操作系统不挂就不会丢失)。

参数0和2是通过上文说到的后台线程来刷盘的。

  • 0:redo log buffer (write) -> Page Cache (fsync) -> 磁盘
  • 2:Page Cache (fsync) -> 磁盘

binlog

binlog是归档日志。主要用于数据备份、主从复制。

与redo log的区别
  1. 适用范围不同:开篇就说了,redo log是InnoDB存储引擎特有的,binlog是都能使用的
  2. 日志格式:binlog有三种格式:ROW、STATEMENT(默认)、MIXED。
    1. STATEMENT记录操作的 SQL(相当于记录了逻辑操作,所以针对这种格式binlog可以被称为逻辑日志 ),主从复制中根据SQL语句重现,但是当记录的SQL中使用了动态函数(uuid, now...),这样就会导致主从数据不一致。
    2. ROW记录行数据被修改成什么样了 (这时就不能称为是逻辑日志 了),产生记录多,导致binlog文件过大。
    3. MIXED:根据情况自动选择日志格式(STATEMENT, ROW)
    4. redo log物理日志,记录的是在某个数据页做了什么修改。比如对 XXX 表空间中的 XXX数据页 ZZZ 偏移量的地方做了 AAA 修改。
  3. 写入方式不同:binlog是追加写,写满一个文件就创建一个新文件接着写。
  4. 用途不同。
主从复制
  1. 主库写入binlog,提交事务,更新数据。
  2. 从库会创建一个专门的 I/O 线程连接主库的log dump线程,来接收主库的binlog日志,然后再把binlog信息写入一个relay log(中继日志),返回给主库"复制成功"的响应。
  3. 从库会创建一个用于回放binlog的线程,去读relay log,然后回放binlog更新存储引擎中的数据,最终实现主从的数据一致性。
什么时候刷盘

首先要知道的是一个事务的binlog不能被拆开(因为要保证原子性)。

在事务执行过程中,会先把binlog存储到binlog cache,binlog cache(通过binlog_cache_size控制单个线程中binlog cache的大小),满了需要暂存到磁盘。

事务提交 时,会把 binlog cache的日志 write Page Cache(binglog文件) ,并清空 binlog cache。通过sync_binlog参数控制fsync到磁盘的时机。
sync_binlog参数:

  • 0:不会fsync,后续由操作系统决定何时存储到磁盘
  • 1:立刻fsync
  • N:等存储了 N 个事务的binlog再调用fsync
两阶段提交

目的:防止在提交事务时, redo log和binlog有一个写入失败( 数据库宕机等原因 ),导致主从数据不一致。

主要方式就是先写redo log,后写binlog

阶段1:准备阶段(Prepare ):写入redo log,将事务状态设为prepare

阶段2:提交阶段(Commit ):写入binlog并持久化到磁盘,成功后,将redo log状态改为 commit

造成问题:

  1. 磁盘 I/O 次数多:一次事务提交至少需要两次刷盘
  2. 锁竞争激烈:为了保证多事务不发生顺序上的混乱

MySQL使用组提交的方式进行了优化,但是我在这里就不多说了。

相关推荐
Lalolander1 小时前
2024信创数据库TOP30之华为Gauss DB
大数据·数据库·科技·华为·系统架构
莳花微语2 小时前
Oracle 11G DataGuard GAP 修复过程(通过主库scn增备恢复)
数据库·oracle
petaexpress3 小时前
云原生和数据库哪个好一些?
数据库·云原生·云原生和数据库哪个好·云原生和数据库
Cristiano永远是goat3 小时前
数据库原理-期末复习基础知识第二弹
数据库
MXsoft6184 小时前
智能运维视角下的网络设备监测与数据分析
大数据·运维·数据库
冧轩在努力4 小时前
redis的应用--分布式锁
数据库·redis·分布式
2021-5-54 小时前
利用 Redis 与 Lua 脚本解决秒杀系统中的高并发与库存超卖问题
数据库·redis·lua
都要好好的O4 小时前
2.mysql 中一条更新语句的执行流程是怎样的呢?
数据库·mysql
夏子曦5 小时前
Redis——主从复制原理
数据库·redis·缓存
zxrhhm6 小时前
SQLServer中使用ISNULL替换为指定的替换值
数据库·sqlserver