《MySQL技术内幕:InnoDB存储引擎第2版》——2.4 Checkpoint技术

2.4 Checkpoint技术

前面已经讲到了,缓冲池的设计目的为了协调CPU速度与磁盘速度的鸿沟。因此页的操作首先都是在缓冲池中完成的。如果一条DML语句,如Update或Delete改变了页中的记录,那么此时页是脏的,即缓冲池中的页的版本要比磁盘的新。数据库需要将新版本的页从缓冲池刷新到磁盘。
倘若每次一个页发生变化,就将新页的版本刷新到磁盘,那么这个开销是非常大的。若热点数据集中在某几个页中,那么数据库的性能将变得非常差。同时,如果在从缓冲池将页的新版本刷新到磁盘时发生了宕机,那么数据就不能恢复了。为了避免发生数据丢失的问题,当前事务数据库系统普遍都采用了Write Ahead Log策略,即当事务提交时,先写重做日志,再修改页。当由于发生宕机而导致数据丢失时,通过重做日志来完成数据的恢复。这也是事务ACID中D(Durability持久性)的要求。
思考下面的场景,如果重做日志可以无限地增大,同时缓冲池也足够大,能够缓冲所有数据库的数据,那么是不需要将缓冲池中页的新版本刷新回磁盘。因为当发生宕机时,完全可以通过重做日志来恢复整个数据库系统中的数据到宕机发生的时刻。但是这需要两个前提条件:
?缓冲池可以缓存数据库中所有的数据;
?重做日志可以无限增大。
对于第一个前提条件,有经验的用户都知道,当数据库刚开始创建时,表中没有任何数据。缓冲池的确可以缓存所有的数据库文件。然而随着市场的推广,用户的增加,产品越来越受到关注,使用量也越来越大。这时负责后台存储的数据库的容量必定会不断增大。当前3TB的MySQL数据库已并不少见,但是3?TB的内存却非常少见。目前Oracle Exadata旗舰数据库一体机也就只有2?TB的内存。因此第一个假设对于生产环境应用中的数据库是很难得到保证的。
再来看第二个前提条件:重做日志可以无限增大。也许是可以的,但是这对成本的要求太高,同时不便于运维。DBA或SA不能知道什么时候重做日志是否已经接近于磁盘可使用空间的阈值,并且要让存储设备支持可动态扩展也是需要一定的技巧和设备支持的。
好的,即使上述两个条件都满足,那么还有一个情况需要考虑:宕机后数据库的恢复时间。当数据库运行了几个月甚至几年时,这时发生宕机,重新应用重做日志的时间会非常久,此时恢复的代价也会非常大。
因此Checkpoint(检查点)技术的目的是解决以下几个问题:
?缩短数据库的恢复时间;
?缓冲池不够用时,将脏页刷新到磁盘;
?重做日志不可用时,刷新脏页。
当数据库发生宕机时,数据库不需要重做所有的日志,因为Checkpoint之前的页都已经刷新回磁盘。故数据库只需对Checkpoint后的重做日志进行恢复。这样就大大缩短了恢复的时间。
此外,当缓冲池不够用时,根据LRU算法会溢出最近最少使用的页,若此页为脏页,那么需要强制执行Checkpoint,将脏页也就是页的新版本刷回磁盘。
重做日志出现不可用的情况是因为当前事务数据库系统对重做日志的设计都是循环使用的,并不是让其无限增大的,这从成本及管理上都是比较困难的。重做日志可以被重用的部分是指这些重做日志已经不再需要,即当数据库发生宕机时,数据库恢复操作不需要这部分的重做日志,因此这部分就可以被覆盖重用。若此时重做日志还需要使用,那么必须强制产生Checkpoint,将缓冲池中的页至少刷新到当前重做日志的位置。
对于InnoDB存储引擎而言,其是通过LSN(Log Sequence Number)来标记版本的。而LSN是8字节的数字,其单位是字节。每个页有LSN,重做日志中也有LSN,Checkpoint也有LSN。可以通过命令SHOW ENGINE INNODB STATUS来观察:

mysql> SHOW ENGINE INNODB STATUS\G;
......
---
LOG
---
Log sequence number 92561351052
Log flushed up to   92561351052
Last checkpoint at  92561351052
......

在InnoDB存储引擎中,Checkpoint发生的时间、条件及脏页的选择等都非常复杂。而Checkpoint所做的事情无外乎是将缓冲池中的脏页刷回到磁盘。不同之处在于每次刷新多少页到磁盘,每次从哪里取脏页,以及什么时间触发Checkpoint。在InnoDB存储引擎内部,有两种Checkpoint,分别为:

?Sharp Checkpoint
?Fuzzy Checkpoint

Sharp Checkpoint发生在数据库关闭时将所有的脏页都刷新回磁盘,这是默认的工作方式,即参数innodb_fast_shutdown=1。
但是若数据库在运行时也使用Sharp Checkpoint,那么数据库的可用性就会受到很大的影响。故在InnoDB存储引擎内部使用Fuzzy Checkpoint进行页的刷新,即只刷新一部分脏页,而不是刷新所有的脏页回磁盘。
这里笔者进行了概括,在InnoDB存储引擎中可能发生如下几种情况的Fuzzy Checkpoint:

?Master Thread Checkpoint
?FLUSH_LRU_LIST Checkpoint
?Async/Sync Flush Checkpoint
?Dirty Page too much Checkpoint

对于Master Thread(2.5节会详细介绍各个版本中Master Thread的实现)中发生的Checkpoint,差不多以每秒或每十秒的速度从缓冲池的脏页列表中刷新一定比例的页回磁盘。这个过程是异步的,即此时InnoDB存储引擎可以进行其他的操作,用户查询线程不会阻塞。
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列表中可用页的数量,该值默认为1024,如:

mysql> SHOW VARIABLES LIKE 'innodb_lru_scan_depth'\G;
*************************** 1. row ***************************
Variable_name: innodb_lru_scan_depth
       Value: 1024
1 row in set (0.00 sec)

Async/Sync Flush Checkpoint指的是重做日志文件不可用的情况,这时需要强制将一些页刷新回磁盘,而此时脏页是从脏页列表中选取的。若将已经写入到重做日志的LSN记为redo_lsn,将已经刷新回磁盘最新页的LSN记为checkpoint_lsn,则可定义:

checkpoint_age = redo_lsn - checkpoint_lsn

再定义以下的变量:

async_water_mark = 75% * total_redo_log_file_size
sync_water_mark = 90% * total_redo_log_file_size

若每个重做日志文件的大小为1GB,并且定义了两个重做日志文件,则重做日志文件的总大小为2GB。那么async_water_mark=1.5GB,sync_water_mark=1.8GB。则:
?当checkpoint_age?当async_water_mark?checkpoint_age>sync_water_mark这种情况一般很少发生,除非设置的重做日志文件太小,并且在进行类似LOAD DATA的BULK INSERT操作。此时触发Sync Flush操作,从Flush列表中刷新足够的脏页回磁盘,使得刷新后满足checkpoint_age可见,Async/Sync Flush Checkpoint是为了保证重做日志的循环使用的可用性。在InnoDB 1.2.x版本之前,Async Flush Checkpoint会阻塞发现问题的用户查询线程,而Sync Flush Checkpoint会阻塞所有的用户查询线程,并且等待脏页刷新完成。从InnoDB 1.2.x版本开始——也就是MySQL 5.6版本,这部分的刷新操作同样放入到了单独的Page Cleaner Thread中,故不会阻塞用户查询线程。
MySQL官方版本并不能查看刷新页是从Flush列表中还是从LRU列表中进行Checkpoint的,也不知道因为重做日志而产生的Async/Sync Flush的次数。但是InnoSQL版本提供了方法,可以通过命令SHOW ENGINE INNODB STATUS来观察,如:

mysql> SHOW ENGINE INNODB STATUS\G;
*************************** 1. row ***************************
  Type: InnoDB
……
LRU len: 112902, unzip_LRU len: 0
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
Async Flush: 0, Sync Flush: 0, LRU List Flush: 0, Flush List Flush: 111736
……
1 row in set (0.01 sec)

根据上述的信息,还可以对InnoDB存储引擎做更为深入的调优,这部分将在第9章中讲述。
最后一种Checkpoint的情况是Dirty Page too much,即脏页的数量太多,导致InnoDB存储引擎强制进行Checkpoint。其目的总的来说还是为了保证缓冲池中有足够可用的页。其可由参数innodb_max_dirty_pages_pct控制:

mysql>SHOW VARIABLES LIKE 'innodb_max_dirty_pages_pct'\G;
*************************** 1. row ***************************
Variable_name: innodb_max_dirty_pages_pct
       Value: 75
1 row in set (0.00 sec)

innodb_max_dirty_pages_pct值为75表示,当缓冲池中脏页的数量占据75%时,强制进行Checkpoint,刷新一部分的脏页到磁盘。在InnoDB 1.0.x版本之前,该参数默认值为90,之后的版本都为75。

时间: 2024-10-25 23:56:39

《MySQL技术内幕:InnoDB存储引擎第2版》——2.4 Checkpoint技术的相关文章

《MySQL技术内幕:InnoDB存储引擎第2版》——第3章 文件

第3章 文件 本章将分析构成MySQL数据库和InnoDB存储引擎表的各种类型文件.这些文件有以下这些. ?参数文件:告诉MySQL实例启动时在哪里可以找到数据库文件,并且指定某些初始化参数,这些参数定义了某种内存结构的大小等设置,还会介绍各种参数的类型. ?日志文件:用来记录MySQL实例对某种条件做出响应时写入的文件,如错误日志文件.二进制日志文件.慢查询日志文件.查询日志文件等. ?socket文件:当用UNIX域套接字方式进行连接时需要的文件. ?pid文件:MySQL实例的进程ID文件

《MySQL技术内幕:InnoDB存储引擎第2版》——2.3 InnoDB体系架构

2.3 InnoDB体系架构 通过第1章读者已经了解了MySQL数据库的体系结构,现在可能想更深入地了解InnoDB存储引擎的架构.图2-1简单显示了InnoDB的存储引擎的体系架构,从图可见,InnoDB存储引擎有多个内存块,可以认为这些内存块组成了一个大的内存池,负责如下工作: ?维护所有进程/线程需要访问的多个内部数据结构. ?缓存磁盘上的数据,方便快速地读取,同时在对磁盘文件的数据修改之前在这里缓存. ?重做日志(redo log)缓冲. -- 后台线程的主要作用是负责刷新内存池中的数据

《MySQL技术内幕:InnoDB存储引擎第2版》——导读

前言 为什么要写这本书 过去这些年我一直在和各种不同的数据库打交道,见证了MySQL从一个小型的关系型数据库发展为各大企业的核心数据库系统的过程,并且参与了一些大大小小的项目的开发工作,成功地帮助开发人员构建了可靠的.健壮的应用程序.在这个过程中积累了一些经验,正是这些不断累积的经验赋予了我灵感,于是有了这本书.这本书实际上反映了这些年来我做了哪些事情,其中汇集了很多同行每天可能都会遇到的一些问题,并给出了解决方案. MySQL数据库独有的插件式存储引擎架构使其和其他任何数据库都不同.不同的存储

《MySQL技术内幕:InnoDB存储引擎第2版》——2.5 Master Thread工作方式

2.5 Master Thread工作方式 在2.3节中我们知道了,InnoDB存储引擎的主要工作都是在一个单独的后台线程Master Thread中完成的,这一节将具体解释该线程的具体实现及该线程可能存在的问题.2.5.1 InnoDB 1.0.x版本之前的Master ThreadMaster Thread具有最高的线程优先级别.其内部由多个循环(loop)组成:主循环(loop).后台循环(backgroup loop).刷新循环(flush loop).暂停循环(suspend loop

《MySQL技术内幕:InnoDB存储引擎第2版》——1.3 MySQL存储引擎

1.3 MySQL存储引擎 通过1.2节大致了解了MySQL数据库独有的插件式体系结构,并了解到存储引擎是MySQL区别于其他数据库的一个最重要特性.存储引擎的好处是,每个存储引擎都有各自的特点,能够根据具体的应用建立不同存储引擎表.对于开发人员来说,存储引擎对其是透明的,但了解各种存储引擎的区别对于开发人员来说也是有好处的.对于DBA来说,他们应该深刻地认识到MySQL数据库的核心在于存储引擎. 由于MySQL数据库的开源特性,用户可以根据MySQL预定义的存储引擎接口编写自己的存储引擎.若用

《MySQL技术内幕:InnoDB存储引擎第2版》——3.2 日志文件

3.2 日志文件 日志文件记录了影响MySQL数据库的各种类型活动.MySQL数据库中常见的日志文件有: ?错误日志(error log) ?二进制日志(binlog) ?慢查询日志(slow query log) ?查询日志(log) 这些日志文件可以帮助DBA对MySQL数据库的运行状态进行诊断,从而更好地进行数据库层面的优化.3.2.1 错误日志 错误日志文件对MySQL的启动.运行.关闭过程进行了记录.MySQL DBA在遇到问题时应该首先查看该文件以便定位问题.该文件不仅记录了所有的错

《MySQL技术内幕:InnoDB存储引擎第2版》——2.7 启动、关闭与恢复

2.7 启动.关闭与恢复 InnoDB是MySQL数据库的存储引擎之一,因此InnoDB存储引擎的启动和关闭,更准确的是指在MySQL实例的启动过程中对InnoDB存储引擎的处理过程. 在关闭时,参数innodb_fast_shutdown影响着表的存储引擎为InnoDB的行为.该参数可取值为0.1.2,默认值为1. ?0表示在MySQL数据库关闭时,InnoDB需要完成所有的full purge和merge insert buffer,并且将所有的脏页刷新回磁盘.这需要一些时间,有时甚至需要几

《MySQL技术内幕:InnoDB存储引擎第2版》——2.2 InnoDB存储引擎的版本

2.2 InnoDB存储引擎的版本 InnoDB存储引擎被包含于所有MySQL数据库的二进制发行版本中.早期其版本随着MySQL数据库的更新而更新.从MySQL 5.1版本时,MySQL数据库允许存储引擎开发商以动态方式加载引擎,这样存储引擎的更新可以不受MySQL数据库版本的限制.所以在MySQL 5.1中,可以支持两个版本的InnoDB,一个是静态编译的InnoDB版本,可将其视为老版本的InnoDB:另一个是动态加载的InnoDB版本,官方称为InnoDB Plugin,可将其视为Inno

《MySQL技术内幕:InnoDB存储引擎第2版》——2.1 InnoDB存储引擎概述

2.1 InnoDB存储引擎概述 InnoDB存储引擎最早由Innobase Oy公司开发,被包括在MySQL数据库所有的二进制发行版本中,从MySQL 5.5版本开始是默认的表存储引擎(之前的版本InnoDB存储引擎仅在Windows下为默认的存储引擎).该存储引擎是第一个完整支持ACID事务的MySQL存储引擎(BDB是第一个支持事务的MySQL存储引擎,现在已经停止开发),其特点是行锁设计.支持MVCC.支持外键.提供一致性非锁定读,同时被设计用来最有效地利用以及使用内存和CPU. Hei