整体思路分析
InnoDB内存缓冲池中的数据page要完成持久化的话,是通过两个流程来完成的,一个是脏页落
盘;一个是预写redo log日志。
保证数据的持久性
当缓冲池中的页的版本比磁盘要新时,数据库需要将新版本的页从缓冲池刷新到磁盘。但是如果
每次一个页发送变化,就进行刷新,那么性能开发是非常大的,于是InnoDB采用了Write Ahead
Log(WAL)策略和Force Log at Commit机制实现事务级别下数据的持久性。WAL要求数据的变更写入到磁盘前,首先必须将内存中的日志写入到磁盘;
Force-log-at-commit要求当一个事务提交时,所有产生的日志都必须刷新到磁盘上,如果日志刷
新成功后,缓冲池中的数据刷新到磁盘前数据库发生了宕机,那么重启时,数据库可以从日志中 恢复数据。
为了确保每次日志都写入到重做日志文件,在每次将重做日志缓冲写入重做日志后,必须调用一
次fsync操作,将缓冲文件从文件系统缓存中真正写入磁盘。 可以通过 innodb_flush_log_at_trx_commit
来控制重做日志刷新到磁盘的策略。
脏页落盘
在数据库中进行读取操作,将从磁盘中读到的页放在缓冲池中,下次再读相同的页时,首先判断
该页是否在缓冲池中。若在缓冲池中,称该页在缓冲池中被命中,直接读取该页。否则,读取磁 盘上的页。
对于数据库中页的修改操作,则首先修改在缓冲池中的页,然后再以一定的频率刷新到磁盘上。
页从缓冲池刷新回磁盘的操作并不是在每次页发生更新时触发,而是通过一种称为CheckPoint的 机制刷新回磁盘。
CheckPoint检查点机制
CheckPoint是为了解决下面几个问题:
- 缩短数据库的恢复时间;
- 缓冲池不够用时,将脏页刷新到磁盘;
- 重做日志不可用时,刷新脏页
当数据库发生宕机时,数据库不需要重做所有的日志,因为Checkpoint之前的页都已经刷新回磁
盘。数据库只需对Checkpoint后的重做日志进行恢复,这样就大大缩短了恢复的时间。
当缓冲池不够用时,根据LRU算法(最少最近使用原则)会溢出最近最少使用的页,若此页为脏页,那么需要强制执行
Checkpoint,将脏页也就是页的新版本刷回磁盘。
当重做日志出现不可用时,因为当前事务数据库系统对重做日志的设计都是循环使用的,并不是让
其无限增大的。重做日志可以被重用的部分是指这些重做日志已经不再需要,当数据库发生宕机
时,数据库恢复操作不需要这部分的重做日志,因此这部分就可以被覆盖重用。如果重做日志还需
要使用,那么必须强制Checkpoint,将缓冲池中的页至少刷新到当前重做日志的位置。
CheckPoint分类
在InnoDB存储引擎内部,有两种Checkpoint,分别为:Sharp Checkpoint、Fuzzy Checkpoint
- sharp checkpoint:在关闭数据库的时候,将buffer pool中的脏页全部刷新到磁盘中
- fuzzy checkpoint:数据库正常运行时,在不同的时机,将部分脏页写入磁盘。仅刷新部分脏页
到磁盘,也是为了避免一次刷新全部的脏页造成的性能问题。
fuzzy checkpoint
Fuzzy Checkpoint分为以下几种:
- Master Thread Checkpoint
- FLUSH_LRU_LIST Checkpoint
- Async/Sync Flush Checkpoint
- Dirty Page too much Checkpoint
Master Thread Checkpoint
在Master Thread中,会以每秒或者每10秒一次的频率,将部分脏页从内存中刷新到磁盘,这个过程是
异步的。正常的用户线程对数据的操作不会被阻塞。
FLUSH_LRU_LIST Checkpoint
FLUSH_LRU_LIST checkpoint是在单独的page cleaner线程中执行的。
MySQL对缓存的管理是通过buffer pool中的LRU列表实现的,LRU 空闲列表中要保留一定数量的
空闲页面,来保证buffer pool中有足够的空闲页面来相应外界对数据库的请求。
当这个空间页面数量不足的时候,发生FLUSH_LRU_LIST checkpoint。
空闲页的数量由innodb_lru_scan_depth参数表来控制的,因此在空闲列表页面数量少于配置的
值的时候,会发生checkpoint,剔除部分LRU列表尾端的页面。
Async/Sync Flush Checkpoint
Async/Sync Flush checkpoint是在单独的page cleaner线程中执行的。
Async/Sync Flush checkpoint 发生在重做日志不可用的时候,将buffer pool中的一部分脏页刷
新到磁盘中,在脏页写入磁盘之后,事物对应的重做日志也就可以释放了。
关于redo_log文件的的大小,可以通过 innodb_log_file_size 来配置。
对于是执行Async Flush checkpoint还是Sync Flush checkpoint,由checkpoint_age以及
async_water_mark和sync_water_mark来决定。
async_water_mark=75%*innodb_log_file_size
sync_water_mark=90%*innodb_log_file_size
- 当checkpoint_age<sync_water_mark的时候,无需执行Flush checkpoint。也就说,redo
log剩余空间超过25%的时候,无需执行Async/Sync Flush checkpoint。 - 当async_water_mark<checkpoint_age<sync_water_mark的时候,执行Async Flush
checkpoint,也就说,redo log剩余空间不足25%,但是大于10%的时候,执行Async Flush
checkpoint,刷新到满足条件1 - 当checkpoint_age>sync_water_mark的时候,执行sync Flush checkpoint。也就说,redo
log剩余空间不足10%的时候,执行Sync Flush checkpoint,刷新到满足条件1。
在mysql 5.6之后,不管是Async Flush checkpoint还是Sync Flush checkpoint,都不会阻
塞用户的查询进程。
由于磁盘是一种相对较慢的存储设备,内存与磁盘的交互是一个相对较慢的过程
由于innodb_log_file_size定义的是一个相对较大的值,正常情况下,由前面两种checkpoint刷新
脏页到磁盘,在前面两种checkpoint刷新脏页到磁盘之后,脏页对应的redo log空间随即释放,
一般不会发生Async/Sync Flush checkpoint。同时也要意识到,为了避免频繁低发生Async/Sync
Flush checkpoint,也应该将innodb_log_file_size配置的相对较大一些。
Dirty Page too much Checkpoint
Dirty Page too much Checkpoint是在Master Thread 线程中每秒一次的频率实现的。
Dirty Page too much 意味着buffer pool中的脏页过多,执行checkpoint脏页刷入磁盘,保证
buffer pool中有足够的可用页面。
Dirty Page 由innodb_max_dirty_pages_pct配置,innodb_max_dirty_pages_pct的默认值在
innodb 1.0之前是90%,之后是75%
重做日志落盘
InnoDB存储引擎会首先将重做日志信息先放入重做日志缓冲中,然后再按照一定频率将其刷新到
重做日志文件。重做日志缓冲一般不需要设置得很大,因为一般情况每一秒钟都会讲重做日志缓 冲刷新到日志文件中。可通过配置参数
innodb_log_buffer_size 控制,默认为8MB。
操作系统的文件系统是带有缓存的,当InnoDB向磁盘写入数据时,有可能只是写入到了文件系统的缓
存中,没有真正的“落袋为安”。
InnoDB的innodb_flush_log_at_trx_commit属性可以控制每次事务提交时InnoDB的行为。
当属性值为0时,事务提交时,不会对重做日志进行写入操作,而是等待主线程按时写入;
当属性值为1时,事务提交时,会将重做日志写入文件系统缓存,并且调用文件系统的fsync,将文
件系统缓冲中的数据真正写入磁盘存储,确保不会出现数据丢失;
当属性值为2时,事务提交时,也会将日志文件写入文件系统缓存,但是不会调用fsync,而是让文
件系统自己去判断何时将缓存写入磁盘。
innodb_flush_log_at_commit是InnoDB性能调优的一个基础参数,涉及InnoDB的写入效率和数
据安全。当参数值为0时,写入效率最高,但是数据安全最低;参数值为1时,写入效率最低,但
是数据安全最高;参数值为2时,二者都是中等水平。一般建议将该属性值设置为1,以获得较高
的数据安全性,而且也只有设置为1,才能保证事务的持久性。
转载:https://blog.csdn.net/baidu_29609961/article/details/105106975