- 什么是redo log
- redo log 是InnoDB的日志文件
- redo log 是保证事务持久性的日志
- redo log 记录的是对数据文件的物理更改, redo log 保证日志先行(WAL),即在持久化数据之前,保证之前的redo log 已经写到了磁盘
- redo log所解决的问题背景
- dirty page :读写数据库是为了提高效率,其实是为了平衡cpu计算速度和磁盘io速度的差距(缓存的基本思想),在内存中设计了缓存池(Buffer Pool),主要包括 LRU List, Flush list, Double write buffer。其中LRU list是取出数据存入的缓存地址,Flush list 是我们通过计算修改了读出的数据后产生的数据,这份数据也会保存在LRU list里,由于这份数据和磁盘文件中的数据已经不一致了,所以称这份数据为 dirty page(InnoDB中,数据管理的最小单位是page)。
- 何时产生dirty page:页面访问/ 修改都被封装为一个 mini-transaction , 当mini-transactin 提交的时候,也就是该 mini-transaction 修改的页面进入 flsuh list 的时候
Mini Transaction(MTR):mtr有属于自己的buffer,redo日志记录在这个buffer中,如果我们想把redo日志写入到磁盘文件中,那mrt维护的 redo日志记录将作为一个事务进行维护提交。正常的 mini transaction流程如下:
- 创建一个mini transaction对象,类型为mtr_t
通过函数mtr_start()开始一个mini transaction,这个过程会初始化一个mini transaction buffer - 通过一系列函数,比如mlog_write_ulint()产生Redo日志记录
- 通过函数mtr_commit()提交一个mini transaction,这个过程将Redo日志记录从mini transaction buffer写到全局的Redo Log Buffer中,同时脏页被添加到buffer pool的flush list中
- 创建一个mini transaction对象,类型为mtr_t
- redo log的产生就是为了解决 dirty page flush to disk 期间出现 server stop 情况,导致我们commit的数据无法在 server start 的时候重新刷到磁盘中的问题。
- redo log如何解决的问题?
- 首先了解下redo log的生命周期
- Redo日志记录首先被mini transaction生成,并填充到mini transaction buffer中。Redo日志记录中包含了在崩溃恢复过程中Redo所需要的必要信息
- 在mtr_commit()的时候,Redo日志记录被移动到全局的内存Redo Log Buffer中。如果有必要的话,Redo Log Buffer会被刷到磁盘,来为别的Redo日志记录腾出空间
- 每个Redo日志记录会关联一个LSN,这种关联关系的建立是在mtr_commit()中完成的,即Redo日志记录从mini transaction buffer中复制到全局的Redo Log Buffer时所确定的。一旦Redo日志记录与LSN关联,那么Redo日志记录在Redo日志文件中的位置也就确定了
当Redo日志记录从全局的Redo Log Buffer写到磁盘文件的时候(written + flushed),就意味着Redo日志记录被持久化到磁盘中了 - 每个Redo日志记录都会关联一个脏页list,这种关系也是通过LSN建立的。一个Redo日志记录必须首先被刷到磁盘,然后才能与脏页建立关联关系。当与这个Redo日志记录所关联的全部脏页都刷到磁盘以后,这个Redo日志记录就没有用了
在数据库的恢复过程中,数据库使用Redo日志记录来重建与之关联的脏页list。
- 什么是LSN: Log Sequence Number, 是redo日志内部的一个偏移量。通过LSN可以把脏页,Redo日志记录,Redo日志文件关联起来。当Redo日志记录被copy到内存中的log buffer的时候,它就获得了一个LSN。每当数据库的页面被修改的时候,都会记录一个Redo日志记录。因此每个数据库的页面都会对应一个LSN。页面的LSN被存储在了页面的header中。页面LSN的含义是:在将这个页面写到磁盘以前,其所对应的Redo日志记录必须先落盘。
- redo log 生成步骤
- mtr_commit()的时候,redo日志记录会写入到 log buffer中。
- 将log buffer中的redo log刷新到磁盘中,这个过程是什么时候触发呢?
a. 每秒刷新一次
b. redo log buffer使用大于1/2进行刷新
c. 事务commit(提交)时候进行刷新
innodb_flush_log_at_trx_commit=0 : log buffer 会 每秒写入到日志文件并刷写(flush)到磁盘。但每次事务提交不会有任何影响,也就是 log buffer 的刷写操作和事务提交操作没有关系。在这种情况下,MySQL性能最好,但如果 mysqld 进程崩溃,通常会导致最后 1s 的日志丢失。
innodb_flush_log_at_trx_commit=1:每次事务提交时,log buffer 会被写入到日志文件并刷写到磁盘。这也是默认值。这是最安全的配置,但由于每次事务都需要进行磁盘I/O,所以也最慢。
innodb_flush_log_at_trx_commit=2:每次事务提交会写入日志文件,但并不会立即刷写到磁盘,日志文件会每秒刷写一次到磁盘。这时如果 mysqld 进程崩溃,由于日志已经写入到系统缓存,所以并不会丢失数据;在操作系统崩溃的情况下,通常会导致最后 1s 的日志丢失。 - redo已经写入到了磁盘文件,满足了日志先行的原则,随后checkpoint,dirty page会从内从中刷到磁盘
- 首先了解下redo log的生命周期
- checkpoint:
- 什么是checkpoint:checkpoint是为了定期将db buffer的内容刷新到data file。当遇到内存不足、db buffer已满等情况时,需要将db buffer中的内容/部分内容(特别是脏数据)转储到data file中。在转储时,会记录checkpoint发生的”时刻“。在故障回复时候,只需要redo/undo最近的一次checkpoint之后的操作。
- checkpoint 解决的问题:
a. 缩短数据库恢复时间
b. buffer pool不够用的时候,会通过checkpoint强制刷新derty page到磁盘
c. redo log 文件不够用的情况下,flush dirty page - checkpoint解决问题的原理
a. 当数据库发生宕机时,数据库不需要重做所有的日志,因为Checkpoint之前的页都已经刷新回磁盘。数据库只需对Checkpoint后的重做日志进行恢复,这样就大大缩短了恢复的时间
b. 当缓冲池不够用时,根据LRU算法会溢出最近最少使用的页,若此页为脏页,那么需要强制执行Checkpoint,将脏页也就是页的新版本刷回磁盘。
c. 当重做日志出现不可用时,因为当前事务数据库系统对重做日志的设计都是循环使用的,并不是让其无限增大的,重做日志可以被重用的部分是指这些重做日志已经不再需要,当数据库发生宕机时,数据库恢复操作不需要这部分的重做日志,因此这部分就可以被覆盖重用。如果重做日志还需要使用,那么必须强制Checkpoint,将缓冲池中的页至少刷新到当前重做日志的位置。
- checkpoint 与 LSN
- LSN分类
a. log sequence number: redo_mem_lsn,redo log buffer 的lsn
b. log flushed up to:redo log file 的lsn,其实这个是最终文件记录的lsn
c. last checkpoint at:checkpoint的lsn,存放在第一个文件头部 - checkpoint 种类:
a. Sharp Checkpoint:发生在数据库关闭时将所有的脏页都刷新回磁盘,这是默认的工作方式,即参数innodb_fast_shutdown=1。但是若数据库在运行时也使用Sharp Checkpoint,那么数据库的可用性就会受到很大的影响。故在InnoDB存储引擎内部使用Fuzzy Checkpoint进行页的刷新,即只刷新一部分脏页,而不是刷新所有的脏页回磁盘。
b. Fuzzy Checkpoint:
Master Thread Checkpoint:以每秒或每十秒的速度从缓冲池的脏页列表中刷新一定比例的页回磁盘,这个过程是异步的,此时InnoDB存储引擎可以进行其他的操作,用户查询线程不会阻塞。
b. 1: FLUSH_LRU_LIST Checkpoint:因为InnoDB存储引擎需要保证LRU列表中需要有差不多100个空闲页可供使用。在InnoDB1.1.x版本之前,需要检查LRU列表中是否有足够的可用空间操作发生在用户查询线程中,显然这会阻塞用户的查询操作。倘若没有100个可用空闲页,那么InnoDB存储引擎会将LRU列表尾端的页移除。如果这些页中有脏页,那么需要进行Checkpoint,而这些页是来自LRU列表的,因此称为FLUSH_LRU_LIST Checkpoint。
而从MySQL 5.6版本,也就是InnoDB1.2.x版本开始,这个检查被放在了一个单独的Page Cleaner线程中进行,并且用户可以通过参数innodb_lru_scan_depth控制LRU列表中可用页的数量
b. 2: Async/Sync Flush Checkpoint:指的是重做日志文件不可用的情况,这时需要强制将一些页刷新回磁盘,而此时脏页是从脏页列表中选取的。若将已经写入到重做日志的LSN记为redo_lsn,将已经刷新回磁盘最新页的LSN记为checkpoint_lsn * checkpoint age = redo_lsn - cp_lsn
低水位 = 75% * 总redo大小
高水位 = 90% * 总redo大小
低水位 >= checkpoint age 不需要刷新
低水位 <= checkpoint age <= 高水位 会强制进行 checkpoint , 根据flush_list的顺序,刷新足够多的脏页,让checkpoint age 小于低水位线
高水位 >= checkpoint age 会强制进行 checkpoint , 根据flush_list的顺序,刷新脏页, 让其满足 低水位 <= checkpoint age >= 高水位
b. 3: Dirty Page too much:即脏页的数量太多,导致InnoDB存储引擎强制进行Checkpoint。其目的总的来说还是为了保证缓冲池中有足够可用的页。其可由参数innodb_max_dirty_pages_pct控制:
- LSN分类
InnoDB redo log
最新推荐文章于 2024-07-24 23:35:30 发布