mysql笔记-日志
update语句执行过程:
- 执行器找引擎取需要更新的这条数据。
- 引擎用索引树搜索找到这一行数据,如果这一行所在数据页本来就是在内存中,那么直接返回给执行器。否则,需要先从磁盘读入内存,然后再返回。
- 执行器拿到引擎给的行数据,进行更新,得到新的一行数据。
- 执行器调用引擎接口,引擎将这行新数据更新到内存中。同时将这个更新操作记录到 redo log buffer里面,在合适的时间才写到磁盘上。
- 一条更新语句执行完成后,记录该语句对应的 binlog,此时记录的 binlog 会被保存到 binlog cache。
- 事务的提交过程有两个阶段:redo log prepared和redo log commit。
- prepared:将 redo log 对应的事务状态设置为 prepare,然后将 redo log 刷新到硬盘;
- commit:执行器将 binlog 刷新到磁盘,接着调用引擎的提交事务接口,将 redo log 状态设置为 commit。
两阶段提交:保证了两个日志文件的数据一致性,但是性能很差。
1、磁盘 I/O 次数高:对于“双1”配置,每个事务提交都会进行两次 fsync(刷盘),一次是 redo log 刷盘,另一次是 binlog 刷盘。
2、锁竞争激烈:在两阶段提交的流程基础上,还需要加一个锁来保证提交的原子性。
redo log作用
由以上过程,可以总结出redo log的作用:
1、崩溃恢复
2、节省的是随机写磁盘的 IO 消耗(转成顺序写)
因为在内存中更新完数据后,为了保证在内存中的数据不丢,因为数据库一宕机,那么内存中的数据就丢失了。最直接的方法就是,当在内存中一更新完数据后,就立刻随机写入磁盘进行更新。这很显然存在问题就是随机写磁盘,IO消耗大,速度慢。
我们引入redo log后,当内存中更新了数据,这个更新记录会被记录在redo log buffer中,然后在合适的时间redo log顺序写入到磁盘中。
这样就可以保证在内存中更新完数据后,如果没写入磁盘,也能通过redo log进行崩溃恢复的效果。
WAL 技术:它的关键点就是先写日志,再写磁盘。也就是说,InnoDB在内存中更新完一条数据后,然后写日志,这个时候更新就算完成了。同时,InnoDB 引擎会在适当的时候,将这个操作记录从 buffer pool 中更新到磁盘里面。在崩溃恢复场景中,InnoDB 如果判断到一个数据页可能在崩溃恢复的时候丢失了更新,就会将它读到内存,然后让 redo log 更新内存内容。更新完成后,又是先写日志,再写磁盘……
redo log怎么进行崩溃恢复的
数据库宕机的时间可以分为两种:
- 事务未提交时宕机
- 事务提交后宕机
事务未提交时宕机,可以有两种方式恢复:
- 还未到【两阶段提交】阶段时,就宕机了,那么通过undo log进行事务回滚。
- 在【两阶段提交】阶段时宕机,
- redo log 处于 prepare 阶段之后、写 binlog 之前,回滚。
- 如果 redo log 里面的事务是完整的,也就是已经有了 commit 标识,则直接提交事务;
- 如果 redo log 里面的事务只有完整的 prepare,则判断对应的事务 binlog 是否存在并完整
- 如果是,则提交事务;
- 否则,回滚事务。
事务提交后宕机,无法回滚,且内存中的脏数据还未及时更新到磁盘,则用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 参数控制)。
参数 innodb_flush_log_at_trx_commit 可取的值有:0、1、2,默认值为 1,这三个值分别代表的策略如下:
-
当设置该参数为 0 时,表示每次事务提交时 ,还是将 redo log 留在 redo log buffer 中 ,该模式下在事务提交时不会主动触发写入磁盘的操作。
-
当设置该参数为 1 时,表示每次事务提交时,都将缓存在 redo log buffer 里的 redo log 直接持久化到磁盘,这样可以保证 MySQL 异常重启之后数据不会丢失。
-
当设置该参数为 2 时,表示每次事务提交时,都只是缓存在 redo log buffer 里的 redo log 写到 Page Cache,Page Cache 是专门用来缓存文件数据的,至于何时再从中写入磁盘由操作系统决定。
redo log文件写满了怎么办
redo log文件长这样:
如果 write pos 追上了 checkpoint,就意味着 redo log 文件满了,这时 MySQL 不能再执行新的更新操作,也就是说 MySQL 会被阻塞(因此所以针对并发量大的系统,适当设置 redo log 的文件大小非常重要),此时会停下来**将 Buffer Pool 中的脏页刷新到磁盘中,然后标记 redo log 哪些记录可以被擦除,接着对旧的 redo log 记录进行擦除,等擦除完旧记录腾出了空间,checkpoint 就会往后移动。**所以redo log只记录未被刷入磁盘的数据的物理日志,已经刷入磁盘的数据都会从 redo log 文件里擦除。
binlog作用
binlog 用于备份恢复、主从复制。
binlog 文件保存的是全量的日志,也就是保存了所有数据变更的情况,理论上只要记录在 binlog 上的数据,都可以恢复,所以如果不小心整个数据库的数据被删除了,得用 binlog 文件恢复数据。
binlog何时刷盘
事务执行过程中,先把日志写到binlog cache,事务提交的时候,再把binlog cache写到 binlog 文件中。
MySQL提供一个 sync_binlog 参数来控制数据库的 binlog 刷到磁盘上的频率:
- sync_binlog = 0 的时候,表示每次提交事务都只 write,不 fsync,后续交由操作系统决定何时将数据持久化到磁盘;
- sync_binlog = 1 的时候,表示每次提交事务都会 ,然后马上执行 fsync;
- sync_binlog =N(N>1) 的时候,表示每次提交事务都 write,但累积 N 个事务后才 fsync。
write就是指把日志写入到文件系统的 page cache,fsync才是将数据持久化到磁盘的操作。