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中,故不会阻塞用户查询线程。
解释下为什么重做日志文件不可用时,这时需要强制将一些脏页刷新回磁盘?
因为我们知道redo的作用是保证数据库的一致性,当数据库异常停机时,需要借助redo+undo进行实例恢复,redo前滚---恢复出buffer pool中的脏数据(包括已经commit还没有刷新到磁盘的,也可能包括没有commit,但是已经刷新到磁盘的,)然后借助undo完成回滚---将没有commit,但是已经刷新到磁盘的数据,回滚到之前的状态。那么为啥重做日志文件不可用时,这时需要强制将一些脏页刷新回磁盘?原因就在于,redo 是循环覆写的,当redo log 文件不可用,也就是说此时所有的redo 文件里面的redo都是实例恢复需要的,也就是不能被覆盖的redo, 那么什么是实例恢复需要的redo呢?就是buffer pool中的的脏数据,还没有刷新到磁盘,而这些脏数据相关的redo是不能被覆盖的,这些redo就是实例恢复需要的redo,所以没有可用的重做日志文件,需要强制将一些脏页刷新回磁盘,这样就会有一些redo是实例恢复不需要的了,也就可以被覆盖了。
4、Dirty Page too much
即脏页的数量太多,导致InnoDB存储引擎强制进行Checkpoint。其目的总的来说还是为了保证缓冲池中有足够可用的页。其可由参数innodb_max_dirty_pages_pct控制:
mysql> SHOW GLOBAL VARIABLES LIKE 'innodb_max_dirty_pages_pct' ;
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| innodb_max_dirty_pages_pct | 75 |
+----------------------------+-------+
innodb_max_dirty_pages_pct值为75表示,当缓冲池中脏页的数量占据75%时,强制进行Checkpoint,刷新一部分的脏页到磁盘。在InnoDB 1.0.x版本之前,该参数默认值为90,之后的版本都为75,其可以通过参数innodb_max_dirty_pages_pct来设置;
总结下redo刷新的条件(因为刷新innodb_buffer_pool中的脏数据之前需要刷新redo,所以触发刷新buffer_pool会同时触发刷新redo):
1)当redo log buffer达到一定比值后,
2)刷新innodb_buffer_pool中的脏数据之前,
3)redo log buffer满的时候,没有可用buffer;
4)每秒刷新一次;
5)commit的时候;
6)数据库关闭时发生harp Checkpoint,触发将所有脏页刷回磁盘
7)手工flush logs;
8)重做日志不可用时,触发刷新innodb_buffer_pool中的脏数据,进而触发redo刷新;
三:MySQL binlog: 主从同步 主库binlog先写入到 binlog_buffer中,然后刷新到磁层磁盘也就是binlog文件,主库dump进程读取的binlog文件,发送给从库;
binlog日志是针对整个MySQL server而言的,前面介绍的redo和undo是针对innodb引擎而言的,binlog的存在就是方便那些不支持事务的引擎表来同步数据到slave;
那么到底是先刷新redo还是先写binlog呢?
伴随着这个问题,我重点说下,MySQL innodb 引擎事务commit的过程:
MySQL为了保证master和slave的数据一致性,就必须保证binlog和InnoDB redo日志的一致性,为此MySQL引入二阶段提交(two phase commit or 2pc),MySQL通过两阶段提交(内部XA的两阶段提交)很好地解决了这一问题,两阶段提交关键在于保证redo刷盘之后才能刷新binlog到底层文件,以 binlog 的写入与否作为事务提交成功与否的标志,最后判断 binlog中是否有 redo里的xid,MySQL5.6以前,为了保证数据库上层二进制日志的写入顺序和InnoDB层的事务提交顺序一致,MySQL数据库内部使用了prepare_commit_mutex锁。但是持有这把锁之后,会导致组提交失败;直到MySQL5.6之后,才解决了这个问题,借助序列来保证binlog刷新也可以组提交;关于redo 和binlog组提交,请看下一篇文章,
事务崩溃恢复过程如下:
1.崩溃恢复时,扫描最后一个Binlog文件,提取其中的xid;
2.InnoDB维持了状态为Prepare的事务链表(commit两阶段提交中的第一阶段,为Prepare阶段,会把事务设置为Prepare状态)将这些事务的xid和Binlog中记录的xid做比较,如果在Binlog中存在,则提交,否则回滚事务。
通过这种方式,可以让InnoDB redo 和Binlog中的事务状态保持一致。
四:简单介绍下MySQL的后台进程:
InnoDB存储引擎是多线程模型,因此其后台有多个不同的后台线程,负责处理不同的任务:
1)Master Thread
Master Thread是一个非常核心的后台线程,主要负责将缓冲池中的数据异步刷新到磁盘,保证数据的一致性。
2)IO Thread
InnoDB存储引擎中大量使用了Async IO来处理写IO请求,这样可以极大提高数据库的性能,而IO Thread的主要工作是负责这些IO请求的回调处理,可以使用show engine innodb status命令查看InnoDB存储引擎中的IO进程:
mysql> show engine innodb status\g;
I/O thread 0 state: waiting for completed aio requests (insert buffer thread)
I/O thread 1 state: waiting for completed aio requests (log thread)
I/O thread 2 state: waiting for completed aio requests (read thread)
I/O thread 3 state: waiting for completed aio requests (read thread)
I/O thread 4 state: waiting for completed aio requests (read thread)
I/O thread 5 state: waiting for completed aio requests (read thread)
I/O thread 6 state: waiting for completed aio requests (read thread)
I/O thread 7 state: waiting for completed aio requests (read thread)
I/O thread 8 state: waiting for completed aio requests (write thread)
I/O thread 9 state: waiting for completed aio requests (write thread)
I/O thread 10 state: waiting for completed aio requests (write thread)
I/O thread 11 state: waiting for completed aio requests (write thread)
Pending normal aio reads: [0, 0, 0, 0] , aio writes: [0, 0, 0, 0] ,
ibuf aio reads:, log i/o’s:, sync i/o’s:
Pending flushes (fsync) log: 0; buffer pool: 0
451 OS file reads, 54 OS file writes, 7 OS fsyncs
3.77 reads/s, 16384 avg bytes/read, 1.05 writes/s, 0.13 fsyncs/s
如上显示的是6个io read thread和4个io write thread,但是关于log的io thread 和insert buffer thread的io thread 只有一个;从MySQL 5.6开始默认是四个io read thread和4个io write thread,并且可以通过innodb_read_io_threads 和innodb_write_io_threads 参数进行设置:
mysql> show variables like '%io_threads%';
+-------------------------+-------+
| Variable_name | Value |
+-------------------------+-------+
| innodb_read_io_threads | 6 |
| innodb_write_io_threads | 4 |
+-------------------------+-------+
2 rows in set (0.00 sec)
3)Purge Thread
事务被提交后,其所使用的undo log可能不再需要,因此需要PurgeThread来回收已经使用并分配的undo页。从InnoDB1.1版本开始,purge操作可以独立到单独的线程中进行,以此来减轻Master Thread的工作,从而提高CPU的使用率、提升存储引擎的性能。可以通过在MySQL数据库的配置文件中添加相关的命令来启用独立的Purge Thread,如下参数:
mysql> show variables like 'innodb_purge_threads';
+----------------------+-------+
| Variable_name | Value |
+----------------------+-------+
| innodb_purge_threads | 1 |
+----------------------+-------+
1 row in set (0.00 sec)
Page Cleaner Thread
4)Page Cleaner Thread
是在InnoDB 1.2.x版本中引入的,其作用是将之前版本中的脏页的刷新操作都放入到单独的进程中来完成,目的就是为了减轻原Master Thread的工作及对于用户查询线程的阻塞,进一步提高InnoDB存储引擎的性能。
然后回答最开始的问题:
在内存中先写undo,然后写redo,至于redo和binlog顺序不确定, 刷盘是先刷undo,然后刷redo,最后刷新binlog;
本文标题:MySQLinnodb引擎的事务执行过程
URL标题:http://6mz.cn/article/gsjghs.html