從MySQL5.5版本開始默認使用InnoDB作為引擎,它擅長處理事務,具有自動崩滿恢復的特性,在日常開發中使用非常廣泛,下面是言方的InnoDB引擎美構圖,主要分為內存結構和磁盤結構兩大部分。?
?內存結構主要包括Buffer Pool、Change Buffer、Adaptive Hash Index和Log Buffer四大組件。
Buffer Pool:緩沖池,簡稱BP。BP以Page頁為單位,默認大小16K,BP的底層采用鏈表數據結構管理Page。在InnoDB訪問表記錄和索引時會在Page頁中緩存,以后使用可以減少磁盤IO操作,提升效率。
緩沖池簡單來說就是一塊內存區域,通過內存的速度來彌補磁盤速度較慢對數據庫性能的影響。在數據庫中進行讀取頁的操作,首先將從磁盤讀到的頁存放在緩沖池中,這個過程稱為將頁"FIX"在緩沖池中。下一次再讀取相同的頁時,首先判斷該頁是否在緩沖池中。若在緩沖池中,稱該頁在緩沖池中被命中。直接讀取該頁。否則讀取磁盤上的頁。對于數據庫中頁的修改操作,則首先修改在緩沖池中的頁,然后再以一定的頻率刷新到磁盤上。這里需要注意的是,頁從緩沖池刷新回磁盤的操作并不是每次頁發生更新時觸發,而是通過一種稱為Checkpoint的機制刷新回磁盤。同樣這也是為了提高數據庫的整體性能。
對于innodb存儲引擎而言,其緩沖池的配置通過參數innodb_buffer_ pool_size來設置。這是影響innodb性能的關鍵參數。具體來看,緩沖池中緩存的數據頁類型有:索引頁,數據頁,undo頁,插入緩沖(insert buffer),自適應哈希索引(adaptive hash index),innodb存儲的鎖信息(lock info),數據字典信息(data dictionary)等。不能簡單的認為,緩沖池只是緩存索引頁和數據頁,它們只是占緩沖池很大的一部分而已。
Page管理機制
? Page根據狀態可以分為三種類型:
? ? ?·free page:空閑page,未被使用
? ? ?·clean page:被使用page,數據沒有被修改過
? ? ?·dirty page:臟頁,被使用page,數據被修改過,頁中數據和磁盤的數據產生了不一致
針對上述三種page類型,InnoDB通過三種鏈表結構來維護和管理
? ? ·free list:表示空閑緩沖區,管理free page
? ? ·flush list:表示需要刷新到磁盤的緩沖區,管理dirty page,內部page按修改時間排序。臟頁即? ? ? ? ? ? ? ? ? ? ? ?存在你flush鏈表,也在LRU鏈表中,但是兩種互不影響,LRU鏈表負責管理page的? ? ? ? ? ? ? ? ? ? ? ? ?可用性和釋放,而flush鏈表負責管理臟頁的刷盤操作。
? ? ·Iru list:表示正在使用的緩沖區,管理clean page和dirty page,緩沖區以midpoint為基點,前? ? ? ? ? ? ? ? ? ? ? 面鏈表稱為new列表區,存放經常訪問的數據,占63%;后面的鏈表稱為old列表區,? ? ? ? ? ? ? ? ? ? ? 存放使用較少數據,占37%。
改進型LRU算法維護
? ? 普通LRU:未尾淘汰法,新數據從鏈表頭部加入,釋放空間時從未尾淘汰
? ? 改性LRU:鏈表分為new和old兩個部分,加入元素時并不是從表頭插入,而是從中間midpoint? ? ? ? ? ? ? ? ? ? ? ? ?位置插入,如果數據很快被訪問,那么page就會向new列表頭部移動,如果數據沒? ? ? ? ? ? ? ? ? ? ? ? ?有被訪問,會逐步向old尾部移動,等待淘汰。
? ? ? ? ? ? ? ? ? ? ?每當有新的page數據讀取到buffer pool時,InnoDb引擎會判斷是否有空閑頁,是否? ? ? ? ? ? ? ? ? ? ? ? ?足夠,如果有就將free page從free list列表刪除,放入到LRU列表中。沒有空閑頁,? ? ? ? ? ? ? ? ? ? ? ? 就會根據LRU算法淘汰LRU鏈表默認的頁,將內存空間釋放分配給新的頁。
BUffer pool配置參數:
show variables like%innodb_page_size%;/查看page頁大小
show variables like 9%innodb_old%;//查看ru list中old列表參數
show variables like9%innodb_buffer%;//查看buffer pool參數
建議:將innodb_buffer_pool_size設置為總內存的60%-80%,innodb_buffer_pool_instances可以設置為多個,這樣可以避免緩存爭奪。|
從innodb1.0.x版本開始,允許有多個緩沖池實例。每個頁根據哈希值平均分配到不同緩沖池實例中。這樣做的好處是減少數據庫內部的資源競爭。增加數據庫的并發處理能力。通過參數innodb_buffer_pool_instances來進行配置。該值默認為1。在配置文件中將innodb_buffer_pool_instances設置為大于1的值就可以得到多個緩沖池實例。
注意:innodb_buffer_pool_size必須大于1GB,生成innodb_buffer_pool多實例才有效,最多支持64個innodb_buffer_pool實例。
?Change Buffer:寫緩沖區,簡稱CB。在進行DML操作時,如果BP沒有其相應的Page數據,并不會立刻將磁盤頁加載到緩沖池,而是在CB記錄緩沖變更,等未來數據被讀取時,再將數據合并恢復到BP中。
ChangeBuffer占用BufferPool空間,默認占25%,最大允許占50%,可以根據讀寫業務量來進行調整。
參數innodb_change_buffer_max size;當更新一條記錄時,該記錄在BufferPool存在,直接在BufferPool修改,一次內存操作。如果該記錄在BufferPool不存在(沒有命中),會直接在ChangeBuffer進行一次內存操作,不用再去磁盤查詢數據,避免一次磁盤1O。當下次查詢記錄時,會先進性磁盤讀取,然后再從ChangeBuffer中讀取信息合并,最終載入BufferPool中。
寫緩沖區,僅適用于非準一普通索引頁,為什么?
如果在索引設置唯一性,在進行修改時,InnoDB必須要做唯一性校驗,因此必須查詢磁盤,做一次I0操作。會直接將記錄查詢到BufferPool中,然后在緩沖池修改,不會在ChangeBufer操作。
Adaptive Hash Index:自適應哈希索引,用于優化對BP數據的查詢。InnoDB存儲引擎會監控對表索引的查找,如果觀察到建立哈希索引可以帶來速度的提升,則建立哈希索引,所以稱之為自適應。InnoDB存儲引擎會自動根據訪問的頻率和模式來為某些頁建立哈希索引。
Log Bufer:日志緩沖區,用來保存要寫入磁盤上log文件(Redo/Undo)的數據,日志緩沖區的內容定期刷新到磁盤log文件中。日志緩沖區滿時會自動將其刷新到磁盤,當遇到BLOB或多行更新的大事務操作時,增加日志緩沖區可以節省磁盤/O。
LogBuffer主要是用于記錄InnoDB引擎日志,在DML操作時會產生Redo和Undo日志。
LogBuffer空間滿了,會自動寫入磁盤。
innodb_flush_log at trxrcommit參數控制日志刷新行為,默認為1
? 0:每隔1秒寫日志文件和刷盤操作(寫日志文件LogBuffer->oS cache,刷盤OS cache->磁盤文? ? ? ? ? 件),最多丟失1秒數據
?1:事務提交,立刻寫日志文件和刷盤,數據不丟失,但是會頻繁10操作
?2:事務提交,立刻寫日志文件,每隔1秒鐘進行刷盤操伸
從上圖大致可以看到innodb有多個內存塊,可以認為這些內存塊組成了一個大的內存池,負責如下工作:
1.維護所有進程/線程需要訪問的多個內部數據結構。
2.緩存磁盤上的數據,方便快速的讀取,同時在對磁盤文件的數據修改之前在這里緩存。
3.重做日志(redo log)緩沖
一.后臺線程的主要作用是負責刷新內存池中的數據,保證緩沖池中的內存緩存的是最新最近的數據。此外將已經修改的數據文件刷新到磁盤文件,同時保證在數據庫發生異常的情況下innodb能恢復正常的運行狀態。
后臺線程:
Innodb存儲引擎是多線程的模型,因此其后臺有多個不同的后臺線程,負責處理不同的任務。
1.Master Thread
Master Thread 是非常核心的后臺線程,主要負責將緩沖池中的數據異步刷新到磁盤,保證數據的一致性,包括臟頁的刷新,合并插入緩沖(insert buffer),undo頁的回收等。
2.IO Thread
在innodb存儲引擎中大量使用了AIO(Async IO)來處理寫IO請求,這樣可以極大提高數據庫的性能。而IO Thread的工作主要負責這些IO請求的回調(call back)處理。在innodb 1.0版本之前共有4個IO Thread,分別是write,read,insert buffer和log IO thread。從innodb 1.0.x版本開始,read thread和write thread分別增大到了4個。可以使用innodb_read_io_threads和innodb_write_io_threads參數進行設置。
3. Purge Thread
事務被提交后,其使用的undo log可能不再需要,因此Purge Thread來回收已經使用并分配的undo頁。在innodb 1.1 版本之前,purge操作僅在innodb存儲引擎的Master Thread中完成。從innodb1.1版本開始,purge操作可以獨立到單獨的線程中進行。以此來減輕Master Thread的工作。從而提高CPU的使用率以及提升存儲引擎的性能。可以通過在配置文件中添加如下參數來開啟獨立的Purge Thread(清洗線程)
?在innodb1.1版本中,即使innodb_purge_threads設為大于1,innodb存儲引擎啟動時也會將其設為1,從innodb1.2版本開始,innodb支持多個Purge Thread,這樣做的目的是為了進一步加快undo頁的回收。同時由于Purge Thread需要離散的讀取undo頁,這樣可以更好的利用磁盤的隨機讀取性能。
4.Page cleaner Thread
page cleaner thread線程是在innodb 1.2.x的版本中引入的。其作用是將之前的版本中的臟頁刷新操作都放入到單獨的線程中來完成。而其目的是為了減輕原Master Thread的工作及對于用戶查詢線程的阻塞,進一步提高innodb存儲引擎的性能。