checkpoint_age>sync_water_mark這種情況一般很少發(fā)生,除非設(shè)置的重做日志文件太小,并且在進(jìn)行類似LOAD DATA的BULK INSERT操作。此時(shí)觸發(fā)Sync Flush操作,從Flush列表中刷新足夠的臟頁(yè)回磁盤(pán),使得刷新后滿足checkpoint_age
可見(jiàn),Async/Sync Flush Checkpoint是為了保證重做日志的循環(huán)使用的可用性。在InnoDB 1.2.x版本之前,Async Flush Checkpoint會(huì)阻塞發(fā)現(xiàn)問(wèn)題的用戶查詢線程,而Sync Flush Checkpoint會(huì)阻塞所有的用戶查詢線程,并且等待臟頁(yè)刷新完成。從InnoDB 1.2.x版本開(kāi)始——也就是MySQL 5.6版本,這部分的刷新操作同樣放入到了單獨(dú)的Page Cleaner Thread中,故不會(huì)阻塞用戶查詢線程。
解釋下為什么重做日志文件不可用時(shí),這時(shí)需要強(qiáng)制將一些臟頁(yè)刷新回磁盤(pán)?
因?yàn)槲覀冎纑edo的作用是保證數(shù)據(jù)庫(kù)的一致性,當(dāng)數(shù)據(jù)庫(kù)異常停機(jī)時(shí),需要借助redo+undo進(jìn)行實(shí)例恢復(fù),redo前滾---恢復(fù)出buffer pool中的臟數(shù)據(jù)(包括已經(jīng)commit還沒(méi)有刷新到磁盤(pán)的,也可能包括沒(méi)有commit,但是已經(jīng)刷新到磁盤(pán)的,)然后借助undo完成回滾---將沒(méi)有commit,但是已經(jīng)刷新到磁盤(pán)的數(shù)據(jù),回滾到之前的狀態(tài)。那么為啥重做日志文件不可用時(shí),這時(shí)需要強(qiáng)制將一些臟頁(yè)刷新回磁盤(pán)?原因就在于,redo 是循環(huán)覆寫(xiě)的,當(dāng)redo log 文件不可用,也就是說(shuō)此時(shí)所有的redo 文件里面的redo都是實(shí)例恢復(fù)需要的,也就是不能被覆蓋的redo, 那么什么是實(shí)例恢復(fù)需要的redo呢?就是buffer pool中的的臟數(shù)據(jù),還沒(méi)有刷新到磁盤(pán),而這些臟數(shù)據(jù)相關(guān)的redo是不能被覆蓋的,這些redo就是實(shí)例恢復(fù)需要的redo,所以沒(méi)有可用的重做日志文件,需要強(qiáng)制將一些臟頁(yè)刷新回磁盤(pán),這樣就會(huì)有一些redo是實(shí)例恢復(fù)不需要的了,也就可以被覆蓋了。
4、Dirty Page too much
即臟頁(yè)的數(shù)量太多,導(dǎo)致InnoDB存儲(chǔ)引擎強(qiáng)制進(jìn)行Checkpoint。其目的總的來(lái)說(shuō)還是為了保證緩沖池中有足夠可用的頁(yè)。其可由參數(shù)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表示,當(dāng)緩沖池中臟頁(yè)的數(shù)量占據(jù)75%時(shí),強(qiáng)制進(jìn)行Checkpoint,刷新一部分的臟頁(yè)到磁盤(pán)。在InnoDB 1.0.x版本之前,該參數(shù)默認(rèn)值為90,之后的版本都為75,其可以通過(guò)參數(shù)innodb_max_dirty_pages_pct來(lái)設(shè)置;
總結(jié)下redo刷新的條件(因?yàn)樗⑿耰nnodb_buffer_pool中的臟數(shù)據(jù)之前需要刷新redo,所以觸發(fā)刷新buffer_pool會(huì)同時(shí)觸發(fā)刷新redo):
1)當(dāng)redo log buffer達(dá)到一定比值后,
2)刷新innodb_buffer_pool中的臟數(shù)據(jù)之前,
3)redo log buffer滿的時(shí)候,沒(méi)有可用buffer;
4)每秒刷新一次;
5)commit的時(shí)候;
6)數(shù)據(jù)庫(kù)關(guān)閉時(shí)發(fā)生harp Checkpoint,觸發(fā)將所有臟頁(yè)刷回磁盤(pán)
7)手工flush logs;
8)重做日志不可用時(shí),觸發(fā)刷新innodb_buffer_pool中的臟數(shù)據(jù),進(jìn)而觸發(fā)redo刷新;
三:MySQL binlog: 主從同步 主庫(kù)binlog先寫(xiě)入到 binlog_buffer中,然后刷新到磁層磁盤(pán)也就是binlog文件,主庫(kù)dump進(jìn)程讀取的binlog文件,發(fā)送給從庫(kù);
binlog日志是針對(duì)整個(gè)MySQL server而言的,前面介紹的redo和undo是針對(duì)innodb引擎而言的,binlog的存在就是方便那些不支持事務(wù)的引擎表來(lái)同步數(shù)據(jù)到slave;
那么到底是先刷新redo還是先寫(xiě)binlog呢?
伴隨著這個(gè)問(wèn)題,我重點(diǎn)說(shuō)下,MySQL innodb 引擎事務(wù)commit的過(guò)程:
MySQL為了保證master和slave的數(shù)據(jù)一致性,就必須保證binlog和InnoDB redo日志的一致性,為此MySQL引入二階段提交(two phase commit or 2pc),MySQL通過(guò)兩階段提交(內(nèi)部XA的兩階段提交)很好地解決了這一問(wèn)題,兩階段提交關(guān)鍵在于保證redo刷盤(pán)之后才能刷新binlog到底層文件,以 binlog 的寫(xiě)入與否作為事務(wù)提交成功與否的標(biāo)志,最后判斷 binlog中是否有 redo里的xid,MySQL5.6以前,為了保證數(shù)據(jù)庫(kù)上層二進(jìn)制日志的寫(xiě)入順序和InnoDB層的事務(wù)提交順序一致,MySQL數(shù)據(jù)庫(kù)內(nèi)部使用了prepare_commit_mutex鎖。但是持有這把鎖之后,會(huì)導(dǎo)致組提交失??;直到MySQL5.6之后,才解決了這個(gè)問(wèn)題,借助序列來(lái)保證binlog刷新也可以組提交;關(guān)于redo 和binlog組提交,請(qǐng)看下一篇文章,
事務(wù)崩潰恢復(fù)過(guò)程如下:
1.崩潰恢復(fù)時(shí),掃描最后一個(gè)Binlog文件,提取其中的xid;
2.InnoDB維持了狀態(tài)為Prepare的事務(wù)鏈表(commit兩階段提交中的第一階段,為Prepare階段,會(huì)把事務(wù)設(shè)置為Prepare狀態(tài))將這些事務(wù)的xid和Binlog中記錄的xid做比較,如果在Binlog中存在,則提交,否則回滾事務(wù)。
通過(guò)這種方式,可以讓InnoDB redo 和Binlog中的事務(wù)狀態(tài)保持一致。
四:簡(jiǎn)單介紹下MySQL的后臺(tái)進(jìn)程:
InnoDB存儲(chǔ)引擎是多線程模型,因此其后臺(tái)有多個(gè)不同的后臺(tái)線程,負(fù)責(zé)處理不同的任務(wù):
1)Master Thread
Master Thread是一個(gè)非常核心的后臺(tái)線程,主要負(fù)責(zé)將緩沖池中的數(shù)據(jù)異步刷新到磁盤(pán),保證數(shù)據(jù)的一致性。
2)IO Thread
InnoDB存儲(chǔ)引擎中大量使用了Async IO來(lái)處理寫(xiě)IO請(qǐng)求,這樣可以極大提高數(shù)據(jù)庫(kù)的性能,而IO Thread的主要工作是負(fù)責(zé)這些IO請(qǐng)求的回調(diào)處理,可以使用show engine innodb status命令查看InnoDB存儲(chǔ)引擎中的IO進(jìn)程:
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個(gè)io read thread和4個(gè)io write thread,但是關(guān)于log的io thread 和insert buffer thread的io thread 只有一個(gè);從MySQL 5.6開(kāi)始默認(rèn)是四個(gè)io read thread和4個(gè)io write thread,并且可以通過(guò)innodb_read_io_threads 和innodb_write_io_threads 參數(shù)進(jìn)行設(shè)置:
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
事務(wù)被提交后,其所使用的undo log可能不再需要,因此需要PurgeThread來(lái)回收已經(jīng)使用并分配的undo頁(yè)。從InnoDB1.1版本開(kāi)始,purge操作可以獨(dú)立到單獨(dú)的線程中進(jìn)行,以此來(lái)減輕Master Thread的工作,從而提高CPU的使用率、提升存儲(chǔ)引擎的性能??梢酝ㄟ^(guò)在MySQL數(shù)據(jù)庫(kù)的配置文件中添加相關(guān)的命令來(lái)啟用獨(dú)立的Purge Thread,如下參數(shù):
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版本中引入的,其作用是將之前版本中的臟頁(yè)的刷新操作都放入到單獨(dú)的進(jìn)程中來(lái)完成,目的就是為了減輕原Master Thread的工作及對(duì)于用戶查詢線程的阻塞,進(jìn)一步提高InnoDB存儲(chǔ)引擎的性能。
然后回答最開(kāi)始的問(wèn)題:
在內(nèi)存中先寫(xiě)undo,然后寫(xiě)redo,至于redo和binlog順序不確定, 刷盤(pán)是先刷undo,然后刷redo,最后刷新binlog;
網(wǎng)站題目:MySQLinnodb引擎的事務(wù)執(zhí)行過(guò)程
本文網(wǎng)址:http://weahome.cn/article/gsjghs.html