之前学习了LRU算法和Mysql缓冲池使用的LRU变体算法,其中有个共同点就是当LRU链表写满以后如果再有新数据进来会淘汰尾部的数据,那么Mysql淘汰这些尾部数据的时候是否会进行什么操作呢?这就是我们在最后提到了一个参数Modified db pages
,即脏页。
1.什么是脏页?
- 脏页,这个名词很抽象从字面意思去看可能很不解,脏页是当内存中的数据页和磁盘中的数据页内容不一致时,这个数据页称之为脏页。因为从操作系统的角度来讲,自己读入的数据被外部所修改等于被污染,所以叫脏页。
- 当内存中的数据页和磁盘中的数据页数据一致,叫干净页。
2.脏页什么时候会刷新?
- 缓冲池(buffer pool)空间不足,也就是LRU链表写满时,新数据进来时淘汰掉的尾部数据脏页。
- redo log不可用时,需要强制将脏页列表中的一些数据页刷入磁盘。
- Mysql在服务器负载较小时,会主动进行刷脏操作。
- Mysql服务正常关闭,会刷新所有脏页。
3.什么是redo log?
InnoDB中两块非常重要的日志,一个是undo log,另外一个就是我们接下来要学习的redo log。前者用来保证事务的原子性以及InnoDB的MVCC(Mutil-Version Concurrency Control),后者用来保证事务的持久性。
那么什么时候写redo log呢?当数据库对数据做修改的时候,需要把数据页从磁盘读到缓冲池中,然后在缓冲池中进行修改。但是InnoDB采用的是WAL(Write Ahead Log)策略来防止数据丢失,也就是事务提交时,先写redo log才会再去修改内存数据页。
redo log的文件名默认以ib_logfile{NUM},存储在my.cnf中datadir目录下面,受以下两个参数控制
- innodb_log_file_size,日志大小
- innodb_log_files_in_group,日志个数,默认是2个。
所以redo log的大小等于innodb_log_files_in_group*innodb_log_file_size。
既然redo log会产生,那么什么时候会被覆盖呢?redo log被设计成可循环使用,当日志文件写满时那些已经被刷入磁盘中的数据就可以被覆盖啦。
WAL(Write Ahead Log),是关系数据库系统中用于提供原子性和持久性(ACID属性中的两个)的一系列技术,ARIES是WAL系列技术常用的算法,在文件系统中WAL通常称为journaling。WAL的主要思想是将元数据的实时变更操作写入日志文件中,然后在系统负载较小时再把日志刷入磁盘。主要是为了减少磁盘的IO操作,此处就不展开学习了。先Mark一下
4.Checkpoint
Checkpoint(检查点),在数据库中一般是用来把redo log脏页刷入磁盘的一个操作,通过LSN保存记录,作用是当发生宕机等crash情况时,再次启动时会查询Checkpoint,在该Checkpoint之后发生的事务修改恢复到磁盘。通俗来解释,就像我们玩一些游戏每过不久就会存一次档,然后如果游戏客户端不幸crash重新进入最近的一次存档即可,同理。
Checkpoint存在的目的:
- 缩短恢复数据时间。
- 缓冲池写满时,淘汰脏页刷入磁盘。
- redo log写满时,进行刷脏操作。
那么怎么查看我们的检查点呢?可以使用命令show engine innodb status来查看:
1 | >show engine innodb status\G; |
1 | Log sequence number | 当前系统LSN最大值,新的日志LSN将在此基础上生成(LSN+新日志的大小)。 |
LSN(Log Sequence Number),LSN是日志空间中每条日志的结束点,用字节偏移量来表示。每个数据页有LSN,redo log也有LSN,Checkpoint亦有LSN。该LSN记录当前数据页最后一次修改的LSN号,用于在恢复数据时对比重做日志LSN号决定是否对该数据页进行恢复数据。可以通俗理解为,存档编号。
5.Checkpoint什么时候会触发?
InnoDB存储引擎有两种Checkpoint,分别是:
- Sharp Checkpoint
- Fuzzy Checkpoint
Sharp Checkpoint发生在数据库服务关闭时,将所有脏页刷入磁盘,此时innodb_fast_shutdown参数的值为1(innodb_fast_shutdown参数的值:0、1、2),这是默认机制。但是考虑到如果数据库在使用时也执行这种机制,数据库的性能会受到影响,所以Fuzzy Checkpoint刷新部分脏页的这种机制产生了。
Fuzzy Checkpoint刷新部分脏页,也分为以下几种方式:
- Master Thread Checkpoint
- FLUSH_LRU_LIST Checkpoint
- Dirty Page too much Checkpoint
- Async/Sync Flush Checkpoint
Master Thread Checkpoint
主线程以每秒或者每十秒从缓冲池的脏页列表(Flush List)刷新一定比例的数据页回磁盘,这个操作过程是异步的不会阻塞线程。
FLUSH_LRU_LIST Checkpoint
InnoDB需要保证LRU链表中有足够空闲页可以使用,在InnoDB1.1.x版本前,如果LRU链表写满有新的数据进来如果淘汰尾部脏页,会触发Checkpoint机制强制进行刷脏操作。该操作是阻塞线程的,所以在InnoDB1.2.x版本开始,这个操作放到Page Cleaner Thread来处理,每次刷新LRU链表脏页的数量受innodb_lru_scan_depth参数控制(默认:1024)。
Dirty Page too much Checkpoint
当LRU链表中脏页数量过多时(比例),InnoDB为了保证缓冲池中有足够多的空闲页可以使用,会强制触发Checkpoint机制进行刷脏操作。此值受innodb_max_dirty_pages_pct参数控制(默认:75%)。
Async/Sync Flush Checkpoint
为了保证redo log循环使用的可重用性,在redo log不可用时会强制触发Checkpoint刷脏操作。在InnoDB1.2.x版本以前,Async Flush Checkpoint会阻塞当前查询线程,Sync Flush Checkpoint会阻塞所有查询线程。InnoDB1.2.X之后放到单独的Page Cleaner Thread来处理。
6.最后
关于Async/Sync Flush Checkpoint刷脏方式的原理有些复杂,这里先Mark一下,暂时不展开学习了。
前面说到的Percona XtraDB
https://www.percona.com/doc/percona-server/8.0/scalability/innodb_io.html