这里写目录标题
- undo log(回滚日志):是 Innodb 存储引擎层生成的日志,实现了事务中的原子性,主要用于事务回滚和 MVCC。
- redo log(重做日志):是 Innodb 存储引擎层生成的日志,实现了事务中的持久性,主要用于掉电等故障恢复;
- binlog (归档日志):是 Server 层生成的日志,主要用于数据备份和主从复制;
undo log
undo log的作用
- 实现事务回滚,保障事务的原子性。事务处理过程中,如果出现了错误或者用户执 行了 ROLLBACK 语句,MySQL 可以利用 undo log 中的历史数据将数据恢复到事务开始之前的状态。
- 实现 MVCC(多版本并发控制)关键因素之一。MVCC 是通过 ReadView + undo log 实现的。undo log 为每条记录保存多份历史数据,MySQL 在执行快照读(普通 select 语句)的时候,会根据事务的 Read View 里的信息,顺着 undo log 的版本链找到满足其可见性的记录。
undo log页记录的是什么
开启事务后,InnoDB 层更新记录前,首先要记录相应的 undo log,如果是更新操作,需要把被更新的列的旧值记下来,也就是要生成一条 undo log,undo log 会写入 Buffer Pool 中的 Undo 页面。
在MySQL的InnoDB存储引擎中,undo log页记录的是事务对数据的修改操作。每个undo log页由多个undo log记录组成,每个记录都对应着一个事务对某个数据行的修改操作。
具体来说,一个undo log记录通常包括以下内容:
-
事务ID(Transaction ID):记录该事务的唯一标识符,用于标识事务的开始和结束。
-
操作类型(Operation Type):记录该操作是一个插入、更新还是删除操作。
-
数据行的物理位置(Physical Location):记录该数据行在磁盘中的物理位置,用于回滚时定位到对应的数据行。
-
原始数据(Original Data):记录该数据行在事务开始之前的原始数据,用于回滚时将数据还原到事务开始之前的状态。
-
其他控制信息(Control Information):包括回滚指针、前后版本号等,用于管理和维护undo log的链表和版本控制。
通过undo log页中记录的原始数据,可以实现事务的回滚操作,将数据还原到事务开始之前的状态。这样,即使事务执行过程中发生了错误或需要回滚,也可以保持数据的一致性和完整性。
需要注意的是,undo log页是在InnoDB存储引擎中以页的形式进行管理的,每个页的大小通常为16KB。在事务提交后,相关的undo log页将被标记为可回收,以便在后续的回滚段清理过程中进行回收和释放。
Buffer Pool
为什么需要Buffer Pool
MySQL 的数据都是存在磁盘中的,那么我们要更新一条记录的时候,得先要从磁盘读取该记录,然后在内存中修改这条记录。那修改完这条记录是选择直接写回到磁盘,还是选择缓存起来呢?当然是缓存起来好,这样下次有查询语句命中了这条记录,直接读取缓存中的记录,就不需要从磁盘获取数据了。为此,Innodb 存储引擎设计了一个缓冲池(Buffer Pool),来提高数据库的读写性能。
有了 Buffer Poo 后:
- 当读取数据时,如果数据存在于 Buffer Pool 中,客户端就会直接读取 Buffer Pool 中的数据,否则再去磁盘中读取。
- 当修改数据时,如果数据存在于 Buffer Pool 中,那直接修改 Buffer Pool 中数据所在的页,然后将其页设置为脏页(该页的内存数据和磁盘上的数据已经不一致),为了减少磁盘I/O,不会立即将脏页写入磁盘,后续由后台线程选择一个合适的时机将脏页写入到磁盘。
Buffer Pool缓存什么
InnoDB 会把存储的数据划分为若干个「页」,以页作为磁盘和内存交互的基本单位,一个页的默认大小为 16KB。因此,Buffer Pool 同样需要按「页」来划分。在 MySQL 启动的时候,InnoDB 会为 Buffer Pool 申请一片连续的内存空间,然后按照默认的16KB
的大小划分出一个个的页, Buffer Pool 中的页就叫做缓存页。此时这些缓存页都是空闲的,之后随着程序的运行,才会有磁盘上的页被缓存到 Buffer Pool 中。
Buffer Pool 除了缓存「索引页」和「数据页」,还包括了 Undo 页,插入缓存、自适应哈希索引、锁信息等等。
redo log
buffer pool是基于内存你的,不可靠。为了防止断电导致数据丢失的问题,当有一条记录需要更新的时候,InnoDB 引擎就会先更新内存(同时标记为脏页),然后将本次对这个页的修改以 redo log 的形式记录下来,这个时候更新就算完成了。后续,InnoDB 引擎会在适当的时候,由后台线程将缓存在 Buffer Pool 的脏页刷新到磁盘里,这就是 WAL (Write-Ahead Logging)技术。
WAL 技术指的是, MySQL 的写操作并不是立刻写到磁盘上,而是先写日志,然后在合适的时间再写到磁盘上。
什么是redo log
redo log 是物理日志,记录了某个数据页做了什么修改,比如对 XXX 表空间中的 YYY 数据页 ZZZ 偏移量的地方做了AAA 更新,每当执行一个事务就会产生这样的一条或者多条物理日志。在 MySQL 中,redo log(重做日志)是一种事务日志,用于记录已经执行的事务对数据库的修改操作。它用于确保事务的持久性和数据的一致性。当一个事务对数据库进行修改操作时,MySQL 首先会将这些修改操作记录到 redo log 中,然后再将修改操作应用到内存中的数据页。这样,即使在事务提交之前发生了故障,数据库可以通过 redo log 中的记录来恢复事务所做的修改。
redo log的作用
- 保证事务的持久性:将事务的修改操作记录到redo log中,即使在事务提交之前发生了故障,数据库可以通过redo log的内容来重新执行事务,确保事务的持久性。
- 提高数据库的性能:将事务的修改操作先记录到redo log中,然后再应用到内存中的数据页。这样可以避免频繁地将数据写入磁盘,提高数据库的性能,将写操作从「随机写」变成了「顺序写」,提升 MySQL 写入磁盘的性能。
在 MySQL 中,redo log 是在 InnoDB 存储引擎中实现的。它以固定大小的日志文件(称为 redo log 文件)的形式存储在磁盘上。当一个事务对数据库进行修改时,相关的修改操作会被追加到 redo log 文件中,而不是直接写入磁盘上的数据文件。
需要注意的是,redo log 是循环写入的,当 redo log 的空间用完时,会从头开始覆盖之前的日志。因此,在设计和配置系统时,需要根据系统的负载和事务的特性来合理设置 redo log 的大小和数量,以确保系统的性能和可靠性。
redo log什么时候刷盘
-
MySQL 正常关闭时;
-
当 redo log buffer 中记录的写入量大于 redo log buffer 内存空间的一半时,会触发落盘;
-
InnoDB 的后台线程每隔 1 秒,将 redo log buffer 持久化到磁盘。
-
每次事务提交时都将缓存在 redo log buffer 里的 redo log 直接持久化到磁盘(此策略由 innodb_flush_log_at_trx_commit 参数控制)
- 当设置该参数为 0 时,表示每次事务提交时 ,还是将 redo log 留在 redo log buffer 中 ,该模式下在事务提交时不会主动触发写入磁盘的操作。
- 当设置该参数为 1 时,表示每次事务提交时,都将缓存在 redo log buffer 里的 redo log 直接持久化到磁盘,这样可以保证 MySQL 异常重启之后数据不会丢失。
- 当设置该参数为 2 时,表示每次事务提交时,都只是缓存在 redo log buffer 里的 redo log 写到 redo log 文件,注意写入到「 redo log 文件」并不意味着写入到了磁盘,因为操作系统的文件系统中有个 Page Cache(如果你想了解 Page Cache,可以看这篇 (opens new window)),Page Cache 是专门用来缓存文件数据的,所以写入「 redo log文件」意味着写入到了操作系统的文件缓存。
innodb_flush_log_at_trx_commit 为 0 和 2 的时候,什么时候才将 redo log 写入磁盘?
InnoDB 的后台线程每隔 1 秒:
- 针对参数 0 :会把缓存在 redo log buffer 中的 redo log ,通过调用
write()
写到操作系统的 Page Cache,然后调用fsync()
持久化到磁盘。所以参数为 0 的策略,MySQL 进程的崩溃会导致上一秒钟所有事务数据的丢失; - 针对参数 2 :调用 fsync,将缓存在操作系统中 Page Cache 里的 redo log 持久化到磁盘。所以参数为 2 的策略,较取值为 0 情况下更安全,因为 MySQL 进程的崩溃并不会丢失数据,只有在操作系统崩溃或者系统断电的情况下,上一秒钟所有事务数据才可能丢失。
这三个参数的应用场景
这三个参数的数据安全性和写入性能的比较如下:
- 数据安全性:参数 1 > 参数 2 > 参数 0
- 写入性能:参数 0 > 参数 2> 参数 1
所以,数据安全性和写入性能是熊掌不可得兼的,要不追求数据安全性,牺牲性能;要不追求性能,牺牲数据安全性。
undo和redo的区别
- 功能:undo log 用于回滚操作和提供 MVCC,而 redo log 用于保证事务的持久性。
- 记录内容:undo log 记录了事务之前的原始数据,而 redo log 记录了已经执行的事务对数据库的修改操作。
- 存储位置:undo log 存储在回滚段中,而 redo log 存储在 redo log 文件中。
- 使用时机:undo log 在事务执行期间记录数据的修改操作,而 redo log 在事务提交之前记录数据的修改操作。
binlog
MySQL 在完成一条更新操作后,Server 层还会生成一条 binlog,等之后事务提交的时候,会将该事物执行过程中产生的所有 binlog 统一写 入 binlog 文件。binlog 文件是记录了所有数据库表结构变更和表数据修改的日志,不会记录查询类的操作,比如 SELECT 和 SHOW 操作。
binlog 作用
- 数据恢复:binlog 可以用于恢复数据库到某个特定的时间点或特定的事务状态。通过使用 binlog,可以将数据库恢复到之前的状态,以应对误操作、数据丢失或系统故障等情况。
- 数据库复制:binlog 可以被用于实现数据库的主从复制。在主从复制中,主数据库将其修改操作记录到 binlog 中,并将 binlog 传输给从数据库,从数据库根据 binlog 中的信息来进行相应的修改操作,从而实现数据的同步复制。
redo log和binlog区别
1、适用对象不同:
- binlog 是 MySQL 的 Server 层实现的日志,所有存储引擎都可以使用;
- redo log 是 Innodb 存储引擎实现的日志;
2、记录内容:
- redo log:redo log 记录了已经执行的事务对数据库的物理修改操作。它包含了在事务提交之前所做的数据修改。
- binlog:binlog 记录了对数据库的逻辑修改操作,即对数据的增删改操作。它记录了对数据的具体 SQL 语句或语句的逻辑表示。
3、写入方式不同:
- binlog 是追加写,写满一个文件,就创建一个新的文件继续写,不会覆盖以前的日志,保存的是全量的日志。
- redo log 是循环写,日志空间大小是固定,全部写满就从头开始,保存未被刷入磁盘的脏页日志。
4、用途不同:
- binlog 用于备份恢复、主从复制;
- redo log 用于掉电等故障恢复。
如果数据数据被删了,能用redo log文件恢复数据吗?
不可以使用 redo log 文件恢复,只能使用 binlog 文件恢复。因为 redo log 文件是循环写,是会边写边擦除日志的,只记录未被刷入磁盘的数据的物理日志,已经刷入磁盘的数据都会从 redo log 文件里擦除。binlog 文件保存的是全量的日志,也就是保存了所有数据变更的情况,理论上只要记录在 binlog 上的数据,都可以恢复,所以如果不小心整个数据库的数据被删除了,得用 binlog 文件恢复数据。
主从复制
MySQL 的主从复制依赖于 binlog ,也就是记录 MySQL 上的所有变化并以二进制形式保存在磁盘上。复制的过程就是将 binlog 中的数据从主库传输到从库上。这个过程一般是异步的,也就是主库上执行事务操作的线程不会等待复制 binlog 的线程同步完成。
MySQL 集群的主从复制过程梳理成 3 个阶段:
- 写入 Binlog:主库写 binlog 日志,提交事务,并更新本地存储数据。
- 同步 Binlog:把 binlog 复制到所有从库上,每个从库把 binlog 写到暂存日志中。
- 回放 Binlog:回放 binlog,并更新存储引擎中的数据。
主从复制还有哪些模型
主要有三种:
- 同步复制:MySQL 主库提交事务的线程要等待所有从库的复制成功响应,才返回客户端结果。这种方式在实际项目中,基本上没法用,原因有两个:一是性能很差,因为要复制到所有节点才返回响应;二是可用性也很差,主库和所有从库任何一个数据库出问题,都会影响业务。
- 异步复制(默认模型):MySQL 主库提交事务的线程并不会等待 binlog 同步到各从库,就返回客户端结果。这种模式一旦主库宕机,数据就会发生丢失。
- 半同步复制:MySQL 5.7 版本之后增加的一种复制方式,介于两者之间,事务线程不用等待所有的从库复制成功响应,只要一部分复制成功响应回来就行,比如一主二从的集群,只要数据成功复制到任意一个从库上,主库的事务线程就可以返回给客户端。这种半同步复制的方式,兼顾了异步复制和同步复制的优点,即使出现主库宕机,至少还有一个从库有最新的数据,不存在数据丢失的风险。
binlog 什么时候刷盘
事务执行过程中,先把日志写到 binlog cache(Server 层的 cache),事务提交的时候,再把 binlog cache 写到 binlog 文件中。