2.1 InnoDB 概述
2.2 InnoDB 版本
2.3 InnoDB 體系架構(gòu)
后臺線程的主要作用是負(fù)責(zé)刷新內(nèi)存池中的數(shù)據(jù)熬甫, 保證緩沖池中的內(nèi)存緩存的是最近的數(shù)據(jù)假抄。 此外將已修改的數(shù)據(jù)文件刷新到磁盤文件, 同時保證在數(shù)據(jù)庫發(fā)生異常的情況下 InnoDB 能恢復(fù)到正常運行的狀態(tài)。
2.3.1 后臺線程
1 Master Thread
主線程主要負(fù)責(zé)將緩沖池中的數(shù)據(jù)異步刷新到磁盤, 保證數(shù)據(jù)的一致性, 包括臟頁的刷新翘簇、合并插入緩沖(Insert Buffer), Undo 頁的回收等儿倒。
2 IO Thread
IO 線程主要負(fù)責(zé) AIO(async IO)請求的回調(diào)(call back)處理版保。 從 InnoDB 1.0.x 開始, read thread 和 write thread 分別增到到了 4 個义桂, 用 innodb_read_io_threads 和 innodb_write_io_threads 參數(shù)進(jìn)行設(shè)置找筝。
上圖可以看到 IO Thread 0 為 insert buffer thread。 IO Thread 1 為 log thread 慷吊。 之后就是 innodb_read_io_threads 及 innodb_write_io_threads 來設(shè)置的讀寫線程袖裕, 且 讀線程的 ID 總是 小于寫線程。?
3 Purge Thread
事務(wù)被提交后溉瓶, 其所使用的 undo log 可能不再需要, 因此需要 purge thread 來回收已經(jīng)使用并分配的 undo 頁。 從 Innodb 1.2 版本開始辆影, Innodb 支持多個 purge thread , 這樣做的目的是為了進(jìn)一步加快 undo 頁的回收。 同時由于 purge thread 需要離散地讀取 undo 頁张足, 這樣也能更進(jìn)一步利用磁盤的隨機讀取性能。
4 Page Cleaner Thread
作用是將之前版本中臟頁的刷新操作都放入到單獨的線程中來完成坎藐。 目的是為了減輕原 master thread 的工作及對于用戶查詢線程的阻塞为牍, 進(jìn)一步提高 Innodb 引擎的性能。
2.3.2 內(nèi)存
1 緩沖池
Innodb 引擎是基于磁盤存儲的岩馍, 并將其中記錄按照頁的方式進(jìn)行管理碉咆。 因此可將其視為基于磁盤的數(shù)據(jù)庫系統(tǒng)。
需要注意蛀恩, 頁從緩沖池刷新回磁盤的操作并不是在每次頁發(fā)生更新時觸發(fā)疫铜, 而是通過一種稱為 checkpoint 的機制刷新回磁盤。 同樣是為了提高數(shù)據(jù)庫的整體性能双谆。
緩沖池的配置通過參數(shù) innodb_buffer_pool_size 來設(shè)置壳咕。
緩沖池中緩沖的數(shù)據(jù)頁類型有: 索引頁, 數(shù)據(jù)頁顽馋, undo 頁谓厘, 插入緩沖(insert buffer),自適應(yīng)哈希索引(adaptive hash index), innodb 存儲的鎖信息(lock info), 數(shù)據(jù)字典信息(data dictionary)等.
參數(shù) innodb_buffer_pool_instances 來配置允許有多少個緩沖池實例寸谜。
從 mysql 5.6 開始庞呕, 通過 information_schema 下的 innodb_buffer_pool_stats 來觀察緩沖狀態(tài)。
2 LRU List程帕, Free List 和 Flush List
通常來說, 數(shù)據(jù)庫中的緩沖池是通過 LRU (Latest Recent Used)算法來管理的地啰。
在 innodb 存儲引擎中愁拭, 緩沖池頁的大小默認(rèn)為 16KB , 同樣用 LRU 算法對緩洪池進(jìn)行管理亏吝。
midpoint insertion strategy: ?新讀取到的頁岭埠, 雖然是最新訪問的頁, 但并不是直接放入到 LRU 列表的首部蔚鸥, 而是放入到 LRU 列表的 midpoint 位置惜论。 默認(rèn)配置下, 該位置在 LRU 列表長度的 5 / 8 出止喷。 midpoint 位置可由參數(shù) innodb_old_blocks_pct 控制馆类。 innodb_old_blocks_pct 默認(rèn)值為 37 , 表示新讀取的頁插入到 LRU 列表尾端的 37% 位置(差不多 3 / 8 處)弹谁。 在 Innodb 中乾巧, 把 midpoint 之后的列表稱為 old 列表句喜, 之前的列表 稱為 new 列表。 可以簡單理解為 new 列表的頁都是最為活躍的熱點數(shù)據(jù)沟于。?
參數(shù) innodb_old_blocks_time : 用于表示頁讀取到 mid 位置后需要等待多久才會被加入到 LRU 列表的熱端咳胃。
database pages 表示 LRU 列表中頁的數(shù)量。
pages made young 顯示了 LRU 列表中頁移動到前端的次數(shù)旷太, 若服務(wù)器運行階段沒有改變 innodb_old_blocks_time 的值展懈, 則 not young 為 0
modified db pages 顯示了臟頁的數(shù)量。
可通過表 innodb_buffer_page_lru 觀察每個 LRU 列表中每個頁的具體信息供璧。
在 LRU 列表中頁被修改后存崖, 該頁為臟頁(dirty page), 即緩沖池中的頁和磁盤上的頁的數(shù)據(jù)不一致嗜傅, 這時數(shù)據(jù)庫會通過 checkpoint 機制將臟頁刷新回磁盤金句, 而 flush 列表中的頁即為臟頁列表。 需要注意吕嘀, 臟頁既存在與 LRU 列表中违寞, 也存在于 Flush 列表中。 LRU 列表用來管理緩沖池中頁的可用性偶房, Flush 列表用來管理將頁刷新回磁盤趁曼。
3 重做日志緩沖
重做日志緩沖一般不需要設(shè)置得很大, 因為一般情況下每一秒會將重做日志緩沖刷新到日志文件棕洋, 因此用戶只需要保證每秒產(chǎn)生的事務(wù)量在扎個緩沖大小之內(nèi)即可挡闰。 該值可由 innodb_log_buffer_size 控制, 默認(rèn) 8MB掰盘。
重做日志在下列三種情況下會將重做日志緩沖中的內(nèi)容刷新到外部磁盤的重做日志文件中:
1 master thread 每一秒將重做日志緩沖刷新到重做日志文件摄悯;
2 每個事務(wù)提交時會將重做日志緩沖刷新到重做日志文件;
3 當(dāng)重做日志緩沖池剩余空間小于 1 / 2 時愧捕, 重做日志換成刷新到重做日志文件奢驯。
4 額外的內(nèi)存池
2.4 CheckPoint 技術(shù)
倘若每次一個頁發(fā)生變化, 就將新頁的版本刷新到磁盤次绘, 這個開銷就非常大了瘪阁, 當(dāng)前事務(wù)數(shù)據(jù)庫系統(tǒng)普遍都采用了 Write Ahead Log 策略, 即當(dāng)事務(wù)提交時邮偎, 先寫重做日志管跺,再修改頁。
checkpoint (檢查點)技術(shù)的目的是解決一下幾個問題:
1 縮短數(shù)據(jù)庫的恢復(fù)時間禾进;
2 緩沖池不夠用時豁跑, 將臟頁刷新到磁盤;
3 重做日志不可用是泻云, 刷新臟頁贩绕。
對 Innodb 引擎而言火的, 其是通過 LSN(Log Sequence Number) 來標(biāo)記版本的。
在 Innodb 引擎內(nèi)淑倾, 有兩種 checkpoint , 分別為:
1 Sharp Checpoint?
2 Fuzzy Checkpoint
Sharp Checkpoint 發(fā)生在數(shù)據(jù)庫關(guān)閉時將所有的臟頁都刷新回磁盤馏鹤, 這是默認(rèn)工作方式。
Fuzzy Checkpoint 使用 Fuzzy Checkpoint 進(jìn)行頁刷新娇哆, 即只刷新一部分臟頁湃累, 而不是刷新所有的臟頁回磁盤。
innodb_lru_scan_depth 控制 LRU 列表中可用頁的數(shù)量碍讨, 默認(rèn)為 1024.
2.5 Master Thread 工作方式
http://www.cnblogs.com/xuanzhi201111/p/4040681.html
主線程邏輯:
2.6 InnoDB 關(guān)鍵特性
2.6.1 插入緩沖 (Insert Buffer)
1 Insert Buffer
Insert Buffer 的使用需要同時滿足以下兩個條件:
1 索引是輔助索引(secondary index)治力;
2 索引不是唯一的(unique)。
2 Change Buffer
參數(shù) innodb_change_buffering, 用來開啟各種 buffer 的選項勃黍。 參數(shù)可選值: inserts宵统, deletes, purges, changes, all, none.
從 Innodb 1.2.x 開始, 通過 innodb_change_buffer_max_size 來控制 change buffer 最大使用內(nèi)存的數(shù)量覆获。 默認(rèn)值為 25 马澈, 表示 最多使用 1 / 4 ?的緩沖池內(nèi)存空間。需要注意弄息, 該參數(shù)的最大有效值為 50.?
3 Insert Buffer 的內(nèi)部實現(xiàn)
Insert Buffer 的數(shù)據(jù)結(jié)構(gòu)是一顆 B+ 數(shù)痊班, 在現(xiàn)在的版本中, 全局只有一棵 Insert Buffer ?B + 樹摹量, 負(fù)責(zé)對所有表的輔助索引進(jìn)行 Insert Buffer涤伐。 其 非葉子節(jié)點存放的是查詢的 search key (鍵值)
4 Merge Insert Buffer
Merge Insert Buffer 的操作可能發(fā)生在一下幾種情況下:
1 輔助索引頁被讀取到緩沖池時;
2 Insert Buffer Bitmap 頁追蹤到該輔助索引頁已無可用空間時缨称;
3 Master Thread
2.6.2 兩次寫 (Double Write)
double write 由兩部分組成凝果, 一部分是內(nèi)存中的 double write buffer, 大小為 2MB睦尽; 另一部分是物理磁盤上共享表空間中連續(xù)的 128 個頁豆村, 即 2 個區(qū), 大小同樣是 2MB骂删。
2.6.3 自適應(yīng)哈希索引 (Adaptive Hash Index)
Innodb 存儲引擎會自動根據(jù)訪問的頻率和模式來自動地為某些熱點頁建立哈希索引。
訪問模式一樣指的是查詢的條件一樣四啰, 若交替進(jìn)行上述查詢宁玫, 那么 Innodb 引擎不會對該頁構(gòu)造 AHI。
哈希索引 只能用來搜索等值的查詢柑晒, 如 select *from table where index_col='xxx'. 而對于其他查找類型欧瘪, 如范圍查找, 是不能使用哈希索引的匙赞, 因此出現(xiàn)了 non-hash searches / s 的情況佛掖。 通過 hash searches:non-hash searches 可以大概了解使用哈希索引后的效率妖碉。?
2.6.4 異步 IO (Async IO)
2.6.5 刷新臨接頁 (Flush Neighbor Page)
參數(shù) innodb_flush_neighbors, 用來控制該特性。 對于傳統(tǒng)機械硬盤建議啟用該特性芥被, 對于固態(tài)硬盤有著超高 IOPS 性能的磁盤欧宜, 則建議將該參數(shù)設(shè)置為 0, 即關(guān)閉次特性拴魄。
2.7 啟動冗茸、關(guān)閉與恢復(fù)
參數(shù) innodb_fast_shutdown 影響著表的存儲引擎 Innodb 的行為。 參數(shù)可取值為 0匹中, 1, 2 夏漱, 默認(rèn)為 1.
為 0 時, ?表示數(shù)據(jù)庫關(guān)閉時顶捷, innodb 需要完成 所有的 full purge 和 merge insert buffer, 并且將所欲的臟頁刷新回磁盤挂绰。 如果在進(jìn)行 Innodb 升級時, 必須將這個參數(shù)調(diào)為 0服赎, 然后再關(guān)閉數(shù)據(jù)庫葵蒂。
為 1 時, ?默認(rèn)值专肪, 表示不需要完成 full purge 和 merge insert buffer 操作刹勃, 單是在緩沖池中的一些數(shù)據(jù)臟頁還是會刷新回磁盤。
為 2 時嚎尤, 不完成 full purge 和 merge insert buffer 操作荔仁, 也不將緩沖池中的數(shù)據(jù)臟頁寫會磁盤, 而是將日志都寫入日志文件芽死。這樣不會有任何事物丟失乏梁, 單下次 Mysql 啟動時, 會進(jìn)行恢復(fù)操作关贵。
需要注意的是遇骑, 在設(shè)置了參數(shù) innodb_force_recovery 大于 0 后, 用戶可以對表進(jìn)行 select , create 和 drop 操作揖曾, 但 Insert 落萎,update 和delete 這類 DML 操作是不允許的。?