undo log|redo log

undo log

undo log 是指回滚日志,用一个比喻来说,就是后悔药,它记录着事务执行过程中被修改的数据。当事务回滚的时候,InnoDB 会根据 undo log 里的数据撤销事务的更改,把数据库恢复到原来的状态。 既然 undo log 是用来回滚的,那么不同的语句对应的 undo log 形态会不一样。但是实际上 undo log 的实现机制要更复杂一点,我这里简化一下模型帮助你记忆。对于INSERT 来说,对应的 undo log 记录了该行的主键。那么后续只需要根据 undo log 里面的 主键去原本的聚簇索引里面删掉记录,就可以实现回滚效果。 对于 INSERT 来说,对应的 undo log 应该是 DELETE。 对于 DELETE 来说,对应的 undo log 应该是 INSERT。 对于 UPDATE 来说,对应的 undo log 也应该是 UPDATE。
对于INSERT 来说,对应的 undo log 记录了该行的主键。那么后续只需要根据 undo log 里面的主键去原本的聚簇索引里面删掉记录,就可以实现回滚效果。
对于 DELETE 来说,对应的 undo log 记录了该行的主键。因为在事务执行 DELETE 的时候,实际上并没有真的把记录删除,只是把原记录的删除标记位设置成了 true。所以这里 undo log 记录了主键之后,在回滚的时候就可以根据 undo log 找到原本的记录,然后再把删除标记位设置成 false。
UPDATE 来说,要更加复杂一些。分为两种情况,如果没有更新主键,那么 undo log里面就记录原记录的主键和被修改的列的原值。
如果更新了主键,那么可以看作是删除了原本的行,然后插入了一个新行。因此 undo log 可以看作是一个 DELETE 原数据的 undo log 再加上插入一个新行的 undo log。
 

redo log

InnoDB 引擎在数据库发生更改的时候,把更改操作记录在 redo log 里,以便在数据库发生崩溃或出现其他问题的时候,能够通过 redo log 来来重做。
InnoDB 引擎读写都不是直接操作磁盘的,而是读写内存里的 buffer pool,后面再把 buffer pool 里面修改过的数据刷新到磁盘里面。这是两个步骤,所以就可能会出现 buffer pool 中的数据修改了,但是还没来得及刷新到磁盘数据库就崩溃了的情况
为了解决这个问题,InnoDB 引擎就引入了 redo log。相当于 InnoDB 先把 buffer pool 里面的数据更新了,再写一份 redo log。等到事务结束之后,就把 buffer pool 的数据刷新到磁盘里面。万一事务提交了,但是 buffer pool 的数据没写回去,就可以用 redo log 来恢复。
顺序写的,所以也是 WAL(write-ahead log) 的一种。也就是说,不管你要修改什么数据,一会修改这条数据,一会修改另外一条数据,redo log 在磁盘上都是紧挨着的。——性能很高
redo log 本身也是先写进 redo log buffer,后面再刷新到操作系统的 pagecache,或者一步到位刷新到磁盘。
0:每秒刷新到磁盘,是从 redo log buffer 到磁盘。
1:每次提交的时候刷新到磁盘上,也就是最安全的选项,InnoDB 的默认值。
2:每次提交的时候刷新到 page cache 里,依赖于操作系统后续刷新到磁盘。
除非把 innodb_flush_log_at_trx_commit 设置成 1,否则其他两个都有丢失的风险。
0:你提交之后,InnoDB 还没把 redo log buffer 中的数据刷新到磁盘,就宕机了。
2:你提交之后,InnoDB 把 redo log 刷新到了 page cache 里面,紧接着宕机了
还有另外两种情况
  1. redo log buffer 快要满了刷盘
  1. 某个事务提交的时候触发了刷新到磁盘的动作
notion image
如果在 redo log 已经刷新到磁盘,然后数据库宕机了,buffer pool 丢失了修改,那么在MySQL 重启之后就会回放这个 redo log,从而纠正数据库里的数据。 如果都没有提交,中途回滚,就可以利用 undo log 去修复 buffer pool 和磁盘上的数据。因为有时,buffer pool 脏页会在事务提交前刷新磁盘,所以 undo log 也可以用来修复磁盘数据

binlog

binlog 主要有两个用途,一是在数据库出现故障时恢复数据。二是用于主从同步,即便是Canal 这一类的中间件本质上也是把自己伪装成一个从节点。
binlog 也有刷新磁盘的问题,不过你可以通过 sync_binlog 参数来控制它。
0:由操作系统决定,写入 page cache 就认为成功了。0 也是默认值,这个时候数据库的性能最好。
N:每 N 次提交就刷新到磁盘,N 越小性能越差。如果 N = 1,那么就是每次事务提交都把 binlog 刷新到磁盘。
你可以对比一下 sync_binlog 和 redo log 的 innodb_flush_log_at_trx_commit 参数,加深印象。

宕机什么情况可恢复

在 redo log 刷新到磁盘之前,都是回滚。
如果 redo log 刷新到了磁盘,那么就是重放 redo log。
是如果 binlog 都已经提交成功了,那么就重放,确保事务一定成功了,否则回滚。而回滚就是一句话:用 undo log 来恢复数据。

中间件的写入语义

中间件写到自身的日志中或者缓冲区,就认为写入成功了。
中间件发起了系统调用,写到了操作系统的 page cache 里面,就认为写入成功了。
中间件强制发起刷盘,数据被持久化到了磁盘上,才认为写入成功了。
定时定量结合,谁先来谁执行
 
分布式情况过半数+1情况安全一些
主节点写入成功,就认为写入成功了。 主节点写入成功,至少有一个从节点写入成功了,就认为写入成功了。 主节点写入成功,大多数从节点写入成功了,就认为写入成功了。 主节点写入成功,特定数量的从节点写入成功了,就认为写入成功了。一般来说,这个“特 定数量”是可配置的。主节点写入成功,全部从节点也写入成功了,才认为写入成功了。
notion image
Loading...
目录
文章列表
王小扬博客
产品
Think
Git
软件开发
计算机网络
CI
DB
设计
缓存
Docker
Node
操作系统
Java
大前端
Nestjs
其他
PHP