Undo Log
用于数据库的回滚操作。保证事务的原子性。(即事务中的所有操作 要么全部成功,要么全部不成功)
在事务执行时,数据库系统将要修改的数据写入到数据库表,同时将这些修改前的数据写入Undo log中。如果事务需要回滚,数据库系统就可以根据Undo log的记录将数据恢复到事务执行前的状态。
实例
A 的余额 500元, B的余额 500 元。 A 向 B 转账 50 元。
事务开始,先将 A 的余额记录到 Undo log 日志中,然后 A 的余额 -50元。
如果此时数据库崩溃或者出现异常,钱没办法转给B了,那此时就可以根据 Undo log日志,执行回滚操作。将A的余额恢复到500元
每次对一条记录进行 增、删、改的操作时,都要把回滚时需要的信息记录到 undo log中:
- 插入一条数据:在日志中记下这条记录的主键,回滚的时候,删除该主键对应的记录。
- 删除一条数据:在日志中记下这条记录的全部信息,回滚的时候,在将这些内容插入到表中。
- 更新一条数据:在日志中记下这条记录的原始值,回滚的时候,将现在的值更新为原始值。
undo log + readView 还可以实现 MVCC(多版本并发控制)
ReadView(读视图):在MVCC中,每个事务都有一个自己的ReadView,用于确定在事务启动的时候那些数据库版本是可见的。
ReadView记录了事务开始时数据库中已提交的事务和未提交的事务的信息,以及事务开始时的系统版本号。
MVCC的实现过程
- 当一个事务需要读取数据时,数据库系统会根据事务的 ReadView和Undo日志来确定读取的数据版本。
- 首先,数据库系统会根据事务的ReadView确定在事务开始时可见的最新数据库版本号。
- 然后,系统根据这个版本号和Undo日志,找到在事务开始时未提交事务所做的修改,将这些修改应用到读取操作上,得到一个对应事务开始时的数据版本。
- 通过这种方式,读取操作可以获取一个一致性的数据快照,即使其他事务正在修改数据,也不会影响到读取操作。
通过ReadView+Undo日志,数据库系统可以实现MVCC机制,确保在事务并发执行时,读取操作可以获取到一个一致性的数据快照,提高了数据库的并发性能和数据一致性。
Redo log
Redo log 保证了 事务的持久性
Redo log用来记录数据页的更改,方便在数据库崩溃或异常关闭时,可以通过重做Redo log中的操作来恢复未完成的事务并保证数据的一致性。
这里先介绍一下 Buffer Pool
Mysql的数据都是存在磁盘中的,当有一条记录需要更新的时候,InnoDB 引擎就会先更新内存(同时标记为脏页),然后将本次对这个页的修改以 redo log 的形式记录下来,这个时候更新就算完成了。
后续,InnoDB 引擎会在适当的时候,由后台线程将缓存在 Buffer Pool 的脏页刷新到磁盘里,这就是 WAL (Write-Ahead Logging)技术。
WAL 技术指的是, MySQL 的写操作并不是立刻写到磁盘上,而是先写日志,然后在合适的时间再写到磁盘上。
Buffer Pool 的作用
- 当读取数据时,如果数据存在于 Buffer Pool 中,客户端就会直接读取 Buffer Pool 中的数据,否则再去磁盘中读取。
- 当修改数据时,如果数据存在于 Buffer Pool 中,那直接修改 Buffer Pool 中数据所在的页,然后将其页设置为脏页(该页的内存数据和磁盘上的数据已经不一致),为了减少磁盘I/O,不会立即将脏页写入磁盘,后续由后台线程选择一个合适的时机将脏页写入到磁盘。
Redo log 的应用
我们如果进行了一个修改数据的操作,数据修改后 将数据缓存到 Buffer Pool中,缓存的数据存在内容中,但是此时mysql突发故障宕机了,那脆弱的内存是不是数据就没了?我们的数据就没办法持久化到磁盘上了。
那此时就体现出来了Redo log的作用了,在进行修改操作时,InnoDB 引擎就会先更新内存(同时标记为脏页),然后将本次对这个页的修改以 redo log 的形式记录下来。
mysql宕机后,当再次恢复正常后,我们执行Redo log中的操作,就可以再次进行原来的修改操作了。
Redo log 的存储位置
Redo log日志直接写入到磁盘中吗? 当然不是
Redo log 也有自己的缓存 — redo log buffer,每当产生一条redo log时,会先写入到redo log buffer,后续在持久化到硬盘中。
Redo log什么时候持久化到硬盘中?
- MySQL 正常关闭时;
- 当 redo log buffer 中记录的写入量大于 redo log buffer 内存空间的一半时,会触发落盘;
- InnoDB 的后台线程每隔 1 秒,将 redo log buffer 持久化到磁盘。
- 每次事务提交时都将缓存在 redo log buffer 里的 redo log 直接持久化到磁盘
Redo log 写满了怎么办?
InnoDB 存储引擎有 1 个重做日志文件组( redo log Group),「重做日志文件组」由有 2 个 redo log 文件组成,这两个 redo 日志的文件名叫 :ib_logfile0
和 ib_logfile1
。
重做日志组采用 循环写 的方式工作。
InnoDB存储引擎会先写 ib_logfile0 文件,当 ib_logfile0 文件被写满的时候,会切换至 ib_logfile1 文件,当 ib_logfile1 文件也被写满时,会切换回 ib_logfile0 文件。
我们知道 redo log 是为了防止 Buffer Pool 中的脏页丢失而设计的,那么如果随着系统运行,Buffer Pool 的脏页刷新到了磁盘中,那么 redo log 对应的记录也就没用了,这时候我们擦除这些旧记录,以腾出空间记录新的更新操作。
Binlog
binlog 文件是记录了所有数据库表结构变更和表数据修改的日志,不会记录查询类的操作,比如 SELECT 和 SHOW 操作。
MySQL 在完成一条更新操作后,Server 层还会生成一条 binlog,等之后事务提交的时候,会将该事物执行过程中产生的所有 binlog 统一写 入 binlog 文件。
rego log 和 binlog 有什么区别?
-
适用对象不同
-
inlog 是Mysql的 Server层实现的日志,所有存储引擎都可以使用;
-
redo log是Innodb存储引擎实现的日志;
-
-
写入方式不同
- binlog 是追加写,写满一个文件,就创建一个新的文件继续写,不会覆盖以前的日志,保存的是全量的日志。
- redo log 是循环写,日志空间大小是固定,全部写满就从头开始,保存未被刷入磁盘的脏页日志。
-
用途不同
-
binlog 用于备份恢复、主从复制;
-
redo log 用于掉电等故障恢复。
-
如果不小心整个数据库的数据被删除了,能使用 redo log 文件恢复数据吗?
不可以使用 redo log 文件恢复,只能使用 binlog 文件恢复。
因为redo log文件是循环写,是会边写边擦除日志的,只记录未被刷入磁盘的数据的物理日志,已经刷入磁盘的数据都会从 redo log 文件里擦除。
binlog 文件保存的是全量的日志,也就是保存了所有数据变更的情况,理论上只要记录在 binlog 上的数据,都可以恢复,所以如果不小心整个数据库的数据被删除了,得用 binlog 文件恢复数据。
主从复制如何实现?
实现主从复制的核心在于 binlog,它记录了mysql上的所有变化并以二进制形式保存在磁盘上。
复制的过程就是将 binlog 中的数据从主库传输到从库上。
具体实现过程:
- MySQL 主库在收到客户端提交事务的请求之后,会先写入 binlog,再提交事务,更新存储引擎中的数据,事务提交完成后,返回给客户端“操作成功”的响应。
- 从库会创建一个专门的 I/O 线程,连接主库的 log dump 线程,来接收主库的 binlog 日志,再把 binlog 信息写入 relay log 的中继日志里,再返回给主库“复制成功”的响应。
- 从库会创建一个用于回放 binlog 的线程,去读 relay log 中继日志,然后回放 binlog 更新存储引擎中的数据,最终实现主从的数据一致性。
主从复制后,你就可以在写数据时只写主库,在读数据时只读从库,这样即使写请求会锁表或者锁记录,也不会影响读请求的执行。