后臺線程
•Master Thread
核心后臺線程,主要負(fù)責(zé)將緩沖池的數(shù)據(jù)異步刷新到磁盤。例如臟頁的刷新,插入緩沖的合并,undo 頁的回收等。
每秒一次的操作:
1.日志緩沖刷新到磁盤,即使該事務(wù)還沒有提交。該操作總是會發(fā)生,這個就是為了再大的事務(wù),提交時間都很短。
2.當(dāng)IO壓力很小時(1s內(nèi)發(fā)生的IO次數(shù)小于5% innodb_io_capacity)合并5% innodb_io_capacity 的插入緩沖。
3.當(dāng)臟頁比例大于 innodb_max_dirty_pages_cnt, 刷新 innodb_io_capacity 個緩沖池中的臟頁到磁盤。否則如果 innodb_adaptive_flush 開啟,則根據(jù)buf_flush_get_desired_flush_rate 來選擇合適刷新臟頁數(shù)量進(jìn)行刷新。
每10秒一次的操作:
1.如果過去10S 內(nèi)IO操作小于 innodb_io_capacity, 刷新 innodb_io_capacity 個緩沖池中的臟頁到磁盤。
2.合并5% innodb_io_capacity 個插入緩沖。
3.將日志緩沖刷新到磁盤。
4.刪除無用的undo頁。
5.如果緩沖池中臟頁比例超過70%,再次刷新 innodb_io_capacity 個臟頁到磁盤。否則刷新10% innodb_io_capacity 個臟頁。
background loop(數(shù)據(jù)庫空閑或者數(shù)據(jù)庫關(guān)閉時):
1.刪除無用的undo頁。
2.合并 innodb_io_capacity 個插入緩沖。
flush loop(數(shù)據(jù)庫空閑):
1.刷新 innodb_io_capacity 個臟頁
•IO Thread
Innodb存儲引擎大量使用了AIO, IO Thread主要負(fù)責(zé)IO請求的回調(diào)。 可使用innodb_read_io_threads和innodb_write_io_threads參數(shù)列表調(diào)整。
•Purge Thread
事務(wù)提交后。該事務(wù)相關(guān)的undolog可能不再需要。Purge Thread就是用來回收不需要的undo頁的。
•PageCleaner Thread
負(fù)責(zé)臟頁的刷新操作。減輕master thread的工作以及對于用戶查詢線程的阻塞。
內(nèi)存緩沖池
對于數(shù)據(jù)庫中頁的修改操作,首先修改在緩沖池中的頁,然后再以一定的頻率刷新到磁盤上。這就意味著不是每次緩沖池中的頁修改時觸發(fā)刷新回磁盤,而是通過checkpoint技術(shù)刷新回磁盤。緩沖池的大小配置可通過 innodb_buffer_pool_size來設(shè)置。
緩沖池的數(shù)據(jù)頁類型有:數(shù)據(jù)頁,索引頁,undo頁,插入緩沖,自適應(yīng)哈希索引,innodb存儲的鎖信息,字典信息。
現(xiàn)在innodb存儲引擎允許多個緩沖池實例。這樣通過hash到不同緩沖池實例來減少鎖的競爭。該參數(shù)可以通過innodb_buffer_pool_instance.
緩沖池是一個很大的內(nèi)存區(qū)域,數(shù)據(jù)庫通過LRU算法來進(jìn)行管理。但是因為考慮到全表掃描的操作。因此沒有采用樸素的LRU算法。LRU列表中加入的midpoint位置。新讀取到的頁,并不是直接放到lru列表的首部,而是midpoint位置。默認(rèn)情況下,在lru列表長度的5/8處。由參數(shù)innodb_old_blocks_pct控制。
插入緩沖
對于非聚集索引的插入和更新操作,Innodb存儲引擎并不是直接插入到索引頁中,而是的Insert Buffer。然后再以一定的頻率進(jìn)行insertbuffer和輔助索引葉子節(jié)點(diǎn)的merge。著通常將多個隨機(jī)插入合并到一個操作中。大大提高了非聚集索引插入的性能。
Innodb使用 insertbuffer 條件:
•索引是非聚集索引
•索引不是unique的(如果是unique, 則又需查找索引來保證unique)
Insert Buffer 內(nèi)部實現(xiàn)
Insert Buffer 的數(shù)據(jù)結(jié)構(gòu)是一棵B+樹。 Mysql 4.1后,全局只有一棵B+樹,負(fù)責(zé)對所有表的輔助索引進(jìn)行insert Buffer. 并且,這棵樹存放在共享表空間里,默認(rèn)情況下即ibdata1。因此,如果僅通過獨(dú)立表空間ibd文件恢復(fù)表中數(shù)據(jù)時,可能會導(dǎo)致失敗。還需要通過insert buffer數(shù)據(jù)恢復(fù)表上的輔助索引。
Insert Buffer 的非葉節(jié)點(diǎn)存放的是查詢key, 構(gòu)造如 space(4字節(jié)) + marker(1字節(jié)) + offset(4字節(jié))。space表示記錄所在表的表空間ID,offset表示頁的偏移量。marker用來兼容老版本。
Insert Buffer 葉子幾點(diǎn)構(gòu)造如 space + marker + offset + metadata + records。 space, marker, offset和前述意義相同。 metadata里的 IBUF_REC_OFFSET_COUNT保存了兩個字節(jié)的整數(shù),用來排序記錄進(jìn)入 Insert Buffer 的順序。通過這個順序回訪呢個得到記錄的正確值。從Insert Buffer 葉子節(jié)點(diǎn)的第5列開始,才是實際插入的各個記錄。
啟用 Insert Buffer索引后,輔助索引頁的記錄可能被插入到 Insert Buffer B+樹中。為了保證每次合并插入緩沖區(qū)成功, 必須要有一塊地方能標(biāo)記每個輔助索引頁的可用空間。 Insert Buffer采用一個特殊的頁來標(biāo)記,該頁的類型為 Insert Buffer Bitmap。每個 Insert Buffer Bitmap頁用來追蹤16384個頁,也就是256個區(qū)。每個Insert Buffer Bitmap 頁都在16384個頁的第二個頁。每個輔助索引頁在Bit map中占用4個字節(jié),這里面主要用于表示輔助索引頁的可用數(shù)量。
合并插入緩沖
Insert Buffer中的記錄在以下情況下合并到真正的輔助索引中:
• 輔助索引頁被讀到緩沖池中;
• Insert Buffer Bitmap 頁追蹤到該輔助索引頁已無可用空間時;
• Master Thread調(diào)度時;
這樣子,對輔助索引頁的多次記錄操作通過一次操作合并到了原有的輔助索引頁中,從而提高性能。
兩次寫(Double Write)
InsertBuffer 給 Innodb 存儲引擎帶來了性能的提升,而兩次寫帶給 Innodb 存儲引擎的是數(shù)據(jù)頁的可靠性。
可能會有疑問,如果發(fā)生寫失敗,那么不是可以通過重做日志進(jìn)行恢復(fù)的嗎?這的確是一個辦法,但是必須知道,重做日志記錄的是頁的物理操作,如偏移量800, 寫'aaa'記錄。但是,如果這個頁已經(jīng)損壞了,對其進(jìn)行重做是沒有意義的。這意味著,在修改頁前,必須有一個正確的頁的副本存在,當(dāng)寫入失效發(fā)生時,先通過頁的副本還原該頁,再進(jìn)行重做,這就是double write。
Double write由兩部分組成,一部分是內(nèi)存中的 double write buffer。 另一部分是在物理磁盤上的共享表空間中的連續(xù)128個頁,大小和內(nèi)存中(2M)一致。對緩沖池中的頁進(jìn)行刷新時,并不直接寫磁盤,而是memcpy到double write buffer. 之后通過 double write buffer 分兩次,每次順序?qū)懭牍蚕肀砜臻g1M數(shù)據(jù),然后馬上調(diào)用fsync同步磁盤。這個寫入因為共享表空間的double write頁是連續(xù)的,因此開銷不是很大。而完成 double write 頁的寫入后,再將double write buffer中的頁寫入各個表空間則是離散的寫入。
如果操作系統(tǒng)在將頁寫入磁盤的過程中發(fā)生了崩潰。那么恢復(fù)時則可以從共享表空間中double write buffer頁找到該頁的副本。將其復(fù)制到表空間再應(yīng)用重做日志。
自適應(yīng)HASH索引
Innodb 存儲引擎會監(jiān)控對表上各索引頁的查詢,如果觀察到建立hash索引可以帶來速度的提升。則建立hash索引,稱之為自適應(yīng)hash索引(AHI).
AHI有一個要求,即對這個頁的連續(xù)訪問模式必須是一樣的. 例如(a, b)這樣的聯(lián)合索引,啟訪問模式可以使:
WHERE a = xxx
WHERE a = xxx and b = yyy
訪問模式一樣就是說查詢的條件一樣。如果交替執(zhí)行上述的查詢操作。則不會建立AHI。
另外,AHI還要求以同一個模式訪問了100次,頁通過該模式訪問了N次,其中N = 頁中記錄 * 1/16
刷新鄰近頁
當(dāng)刷新一個臟頁時,Innodb存儲引擎會通過檢測該頁所在區(qū)的所有頁,如果是臟頁,會一起進(jìn)行刷新。
異步IO
Innodb 采用異步IO的方式來處理磁盤操作。
Check Point技術(shù)
為了避免數(shù)據(jù)丟失的問題,事物數(shù)據(jù)庫系統(tǒng)一般都采用了write ahead log策略。即事物提交時,先寫重做日志,再修改頁。
但是重做日志不可能無限增大,緩沖值(未刷新到磁盤的臟頁)也不可能無限大。即便真可以無限大,數(shù)據(jù)庫宕機(jī)后恢復(fù)時間也會很長。所以就需要 Check Point技術(shù),該技術(shù)可以解決:
• 縮短數(shù)據(jù)庫恢復(fù)的時間;
• 緩沖池不夠用時,可以將臟頁刷新到磁盤;
• 重做日志不可用時(重做日志都是循環(huán)利用的),刷新臟頁到磁盤;
數(shù)據(jù)庫宕機(jī)后重啟時,不需要重做所有的日志了。因為 Check Point之前的頁都已經(jīng)刷新到磁盤,數(shù)據(jù)庫只需對Check Point后的重做日志進(jìn)行恢復(fù)即可。從而大大縮短恢復(fù)時間。
對于Innodb 而言,其實通過 LSN ( Log Sequence Number) 來比較版本的。 LSN 是一個8字節(jié)的數(shù)字。 每個頁有LSN, 重做日志有LSN, CheckPoint 也有LSN??梢酝ㄟ^下述命令觀察到
mysql> show engine innodb status\G;
.............
Log sequence number 92561351052
Log flushed up to 92561351052
Last checkpoint at 92561351052
以上這篇InnoDb 體系架構(gòu)和特性詳解 (Innodb存儲引擎讀書筆記總結(jié))就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
您可能感興趣的文章:- Mysql5.5 InnoDB存儲引擎配置和優(yōu)化
- MySQL存儲引擎總結(jié)
- 淺談MySQL存儲引擎選擇 InnoDB與MyISAM的優(yōu)缺點(diǎn)分析
- MySQL存儲引擎 InnoDB與MyISAM的區(qū)別
- innodb存儲引擎修改表共享空間為獨(dú)立空間
- 深入探討:MySQL數(shù)據(jù)庫MyISAM與InnoDB存儲引擎的比較