看了姜老師的技術內幕,做了如下筆記
Innodb線程:
innodb是多線程模型,有多個後臺線程負責處理不同任務
1、主線程
負責將緩衝池中的數據異步刷新到磁盤,髒頁刷新,合併插入緩衝,undo頁回收等
2、IO線程
innodb存儲引擎中使用了大量AIO(異步io)來處理IO請求,IO線程主要負責這些IO請求的回調。
3、purge線程
事務提交後,其所使用的undolog可能不再需要,因此需要purge thread來回收。
4、page cleaner 線程
負責刷新髒頁
Innodb的內存:
1、緩衝池(innodb_buffer_pool)
Innodb存儲引擎是基於磁盤存儲的,並將其中的記錄按照頁的方式進行管理。由於CPU與磁盤速度之間的鴻溝,基於磁盤的數據庫系統,通常使用緩衝池技術提高數據庫的整體性能。
緩衝池可以理解爲一塊內存區域,在數據庫中讀取頁的操作,首先將磁盤中讀到的頁放在緩衝池中,下次再讀相同的頁時,判斷是否在緩衝池中,在就直接讀取,即命中。不在就到磁盤中去讀取。
對於數據庫中頁的修改,首先修改緩衝池中的頁,然後再以一定頻率刷回磁盤。注意:頁從緩衝池刷回磁盤並不是每次頁變更了都會觸發,而是通過檢查點機制刷新回磁盤。
緩衝池中緩存的數據頁類型有:索引頁,數據頁,undo頁,插入緩衝,自適應哈希,innodb鎖信息,數據字典信息等。
2、LRU list、Free list、Flush list
LRU列表
數據庫中的緩衝池是通過LRU(最近最少使用)算法來進行管理的,innodb對LRU算法進行了一些優化,在LRU列表中加入了midpoint位置,默認情況下,該位置位於LRU列表長度的5/8處。
在midpoint之前的列表稱爲new,之後的稱爲old,可以簡單理解爲new列表中的頁都是活躍的熱點頁。
mid位置頁升爲熱點數據需要等待參數innodb_old_blocks_time,已保證儘量不將LRU列表的將熱點數據刷出。
Free列表
數據庫剛啓動時,LRU列表爲空,所有頁都存在Free列表中,要從緩衝池分頁時,先從Free列表查看有沒有空閒頁,有,將該頁從Free列表刪除,放到LRU列表中。沒有,根據LRU算法,淘汰LRU列表末尾的頁,將內存空間分配給新的頁。
LRU list包含unzip_LRU list,LRU list頁大小爲16K,unzip_LRU list的頁大小可能爲1k、2k、4k、8k。
unzip_LRU列表對不同壓縮頁大小的頁進行分別管理,其次通過夥伴算法進行內存的分配。
例如需要從緩衝池申請一個4k的頁,檢查4k的unzip_LRU列表是否有空閒頁,有,直接使用,沒有,查找8k的unzip_LRU列表,若有空閒頁,將其分爲2個4K的頁,存到4k的unzip_LRU列表,若沒有空閒頁,則將LRU列表一個16k的頁,拆成一個8k和2個4k的頁,存入對應的unzip_LRU列表。
Flush列表
LRU列表中的頁被修改後,稱爲髒頁,即緩衝池中的頁和磁盤上的頁不一致。這時,數據庫會通過checkpoint機制將髒頁刷回磁盤。
Flush列表中的頁即爲髒頁,髒頁既存在於LRU列表,也存在於Flush列表。
LRU列表用來管理緩衝池中頁的可用性,Flush列表用來管理將頁刷新回磁盤,兩者互不影響。
3、重做日誌緩衝(redo log buffer)
innodb存儲引擎先將重做日誌信息放入這個緩衝區,再按照一定頻率將其刷新到重做日誌文件,用戶只需要保證每秒的事務不超過這個緩衝大小即可。默認8M
在下面三種情況下,會將重做日誌緩衝中的內容刷新到重做日誌:
1)、主線程,每一秒將重做日誌緩衝刷新到重做日誌文件。
2)、每個事務提交時,會將重做日誌緩衝刷新到重做日誌文件。
3)、當重做日誌緩衝大小小於1/2時,會將重做日誌緩衝刷新到重做日誌文件。
checkpoint技術
檢查點技術主要解決以下幾個問題:
1)、縮短數據庫恢復時間
當數據庫宕機時,數據庫不需要重做所有的日誌,checkpoint之前的已經刷回磁盤,只需要重做checkpoint之後的日誌,大大減少了恢復時間。
2)、緩衝池不夠時,將髒頁刷新到磁盤
當緩衝池不夠用時,會溢出最近最少使用的頁,如果這個頁是髒頁,那麼強制checkpoint,將髒頁刷新回磁盤。
3)、重做日誌不可用時,刷新髒頁
在innodb中checkpoint分爲兩種:
Sharp checkpoint:在數據庫關閉時,將所有髒頁刷新回磁盤,默認的。
Fuzzy checkpoint:只刷新一部分髒頁到磁盤。
可能發生Fuzzy checkpoint的幾種情況:
1)、master thread checkpoint
差不多每10秒,從髒頁列表刷新一部分髒頁到磁盤。
2)、flush_LRU_list checkpoint
innodb需要保證LRU列表有innodb_lru_scan_depth個空閒頁可以使用,如果沒有,就會從lru列表末尾移除,如果移除的有髒頁,就進行checkpoint。
3)、異步/同步 Flush checkpoint
4)、dirty page too much checkpoint
當緩衝池中髒頁數量大於innodb_max_dirty_pages_pct,強制checkpoint。
Master thread
master thread具有最高的線程優先級,由多個循環組成:主循環loop、後臺循環backgroup loop、刷新循環flush loop、暫停循環suspend loop。master thread會根據數據庫運行狀態,在這些循環中切換。
loop循環,分爲每1秒操作和每10秒操作:
每1秒:
1)、日誌刷新緩衝刷新到磁盤,即使這個事務沒有提交(總是)
2)、合併插入緩衝(可能)(innodb判斷前1秒發生的IO次數是否小於innodb_io_capacity的5%次,則合併緩衝innodb_io_capacity的5%)
3)、至多刷新innodb_io_capacity個緩衝池中的髒頁到磁盤(可能)(判斷當前緩衝池中髒頁的比例是否超過了innodb_max_dirty_pages_pct)
4)、當前沒有用戶活動,則切換到backgroup loop(可能)
每10秒:
1)、刷新innodb_io_capacity個髒頁到磁盤(可能)(innodb判斷過去10s內io是否小於innodb_io_capacity次)
2)、合併innodb_io_capacity的5%個插入緩衝(總是)
3)、將日誌緩衝刷到磁盤(總是)
4)、刪除無用的undo頁(總是)
5)、刷新innodb_io_capacity個或innodb_io_capacity的10%個髒頁到磁盤(總是)(判斷緩衝池中的髒頁比例,如果大於70%刷新innodb_io_capacity個,小於70%刷新innodb_io_capacity的10%個)
backgroup loop:
1)、刪除無用的undo頁(總是)
2)、合併innodb_io_capacity個插入緩衝(總是)
3)、跳回到主循環(總是)
4)、不斷刷新innodb_io_capacity個頁直到符合條件(可能跳到flush loop中完成)
Innodb關鍵特性
1)、插入緩衝
並不是所有的主鍵插入都是順序的,例如UUID這樣的主鍵值或者主鍵爲自增,但插入爲指定值而不是null值,同樣可能會出現非連續插入的現象。
對於非聚集索引的插入或更新操作,並不是每次都直接插入到索引頁。先判斷插入的非聚集索引頁是否在緩衝池中,在,直接插入,不在,先放到insert buffer中。然後再以一定頻率進行Insert buffer和索引頁子節點的合併操作。
insert buffer使用要滿足兩個條件:
a、索引是輔助索引
b、索引不唯一
2)、兩次寫
刷新髒頁時,先將髒頁刷到double write buffer中(2M),再從double write buffer中分兩次(1次1M)順序寫入磁盤上共享表空間的連續128個頁(2M),然後再從double write buffer離散的寫入磁盤,如果寫入失敗了再去共享表空間裏拿副本來恢復。
3)、自適應哈希
AHI是通過緩衝池B+樹頁來夠造的。innodb會根據訪問頻率和模式,自動爲熱點頁添加hash索引。
添加hash索引的條件:
a、連續以同一模式訪問100次
b、頁以同一模式訪問N次,N=頁中記錄*1/16
4)、異步IO
用戶可以發出一個io請求後,跟着再發出一個io請求,當全部IO請求發送完畢後,等待所有IO操作完成,這就是AIO。即不用等一個IO完成才能再發出一個IO。
AIO會判斷多個頁是否是連續的,如果是,會進行merge操作,合併爲一個IO,這就提升了IOPS。
5)、刷新鄰接頁
當刷新一個髒頁時,innodb會檢查該頁所在的區的所有頁,如果是髒頁,那麼就一起刷新。固態硬盤可以考慮關閉,機械硬盤建議開啓。參數爲<innodb_flush_neighbors>0關閉、1開啓。