一、InnoDB 體系架構
InnoDB 存儲引擎有多個記憶體塊,可以認為這些記憶體塊組成了一個大的記憶體池,負責如下工作:
- 維護所有程序/線程需要通路的多個内部資料結構。
- 緩存磁盤上的資料,友善快速的讀取,同時對磁盤檔案的資料修改之前在這裡進行緩存。
- 重做日志(redo log)緩沖。
背景線程的主要作用是負責重新整理記憶體池中的資料,保證緩沖池中的記憶體緩存的是最近的資料。同時将已修改的資料檔案重新整理到磁盤檔案,同時保證在資料庫發生異常的情況下 InnoDB 能恢複到正常運作狀态。
通過 SHOW ENGINE INNODB STATUS 可以觀察到 INNODB 存儲引擎的運作情況。
SHOW ENGINE INNODB STATUS
複制
二、記憶體池
緩沖池簡單來說就是一塊記憶體區域,通過記憶體的速度來彌補磁盤速度較慢對資料庫性能的影響。緩沖池的大小直接影響着資料庫的整體性能,可以通過配置參數 innodb_buffer_pool_size 來設定。
SHOW VARIABLES LIKE 'innodb_buffer_pool_size'
複制
并且 InnoDB 允許有多個緩存池執行個體,每個 PAGE 根據哈希值平均配置設定到不同緩沖池執行個體中,這樣做的好處是減少資料庫内部的資源競争,增加資料庫的并發處理能力,可以通過配置參數 innodb_buffer_pool_instances 來設定。
SHOW VARIABLES LIKE 'innodb_buffer_pool_instances'
複制
通常來說,資料庫中的緩存池是通過 LRU(Lastest Recent Used,最近最少使用)算法來進行管理的,緩存池的預設機關是 "頁",一頁預設 16 KB。
從 InnoDB 1.2 版本開始,可以通過 INNODB_BUFFER_POOL_STATS 來觀察緩存池的運作狀态。
SELECT
POOL_ID,
HIT_RATE '緩存池的命中率',
PAGES_MADE_YOUNG AS '緩存池 old 部分加入到 new 部分的次數',
PAGES_NOT_MADE_YOUNG '緩存池 new 部分加入到 old 部分的次數'
FROM information_schema.INNODB_BUFFER_POOL_STATS
複制
重做日志緩存是用來存放重做日志資訊的,一般不需要設定得過大,因為一般情況下每一秒鐘都會将重做日志緩存重新整理到日志檔案,一般設定 8MB 就足以滿足絕大部分得應用,可通過 INNODB_LOG_BUFFER_SIZE 參數控制。
SHOW VARIABLES LIKE 'INNODB_LOG_BUFFER_SIZE'
複制
目前事務資料庫系統普遍都采用了 WriteAhead Log 政策,即當事務送出時,先寫重做日志,再修改頁。是以,重做日志的作用是對資料庫系統中的資料進行恢複(當資料庫系統異常當機的時候)。
額外記憶體池是用來配置設定一些資料結構本身的記憶體,例如緩沖池中的幀緩存(frame buffer)、緩沖控制對象(innodb_buffer_pool)。
三、背景線程
Master Thread 是一個非常核心的背景線程,主要負責将緩存池中的資料異步重新整理到磁盤,保證資料的一緻性,包括髒頁的重新整理、合并插入緩存(INSERT BUFFER)、UNDO 頁的回收等。
IO Thread 的工作主要是負責 IO 請求的回調處理(InnoDB 存儲引擎中大量的使用了 AIO 來處理寫 IO 請求)。
SHOW VARIABLES LIKE 'INNODB_%io_threads'
複制
PurgeThread 是在 InnoDB 1.1.x 版本中引入的。用來回收已經使用并配置設定的 undo 頁以減輕 Master Thread 的工作量 ,因為事務被送出後,其所使用的 undolog 可能不再需要。
SHOW VARIABLES LIKE 'INNODB_purge_threads'
複制
Page Cleaner Thread 是在 InnoDB 1.2.x 版本中引入的。其作用是将之前版本的髒頁重新整理操作放入到單獨的線程中來完成以減輕 Master Thread 的工作量。
四、其他
InnoDB 存儲引擎開創性地設計了 Insert Buffer(插入緩沖),對于非聚簇索引的插入或更新操作,不是每一次直接插入到索引頁中,而是先判斷插入的非聚簇索引頁是否在緩沖池中,若在,則直接插入;若不在,則先放入到一個 Insert Buffer 對象中,然後再以一定的頻率和情況進行 Insert Buffer 和輔助索引頁子節點的 merge(合并)操作,這時通常能将多個插入合并到一個操作中(因為在一個索引頁中),這就大大提高了對于非聚簇索引插入的性能。
doublewrite(兩次寫)由兩部分組成,一部分是記憶體中的 doublewrite buffer,大小為 2MB,另一部分是實體磁盤上共享表空間中連續的 128個頁,即2個區,大小同樣是 2MB。在對緩沖池的髒頁進行重新整理時,并不直接寫磁盤,而是會通過 memcpy 函數将髒頁先複制到記憶體中的 doublewrite buffer,之後通過 doublewrite buffer 再分兩次,每次 1MB 順序地寫入共享表空間的實體磁盤上,然後馬上調用 fsync 函數,同步磁盤,避免緩沖寫帶來的問題。如果作業系統在将頁寫入磁盤的過程中發生了崩潰,在恢複過程中,InnoDB 存儲引擎可以從共享表空間中的 doublewrite 中找到該頁的一個副本,将其複制到表空間檔案,再應用重做日志。
SHOW GLOBAL STATUS LIKE 'INNODB_dblwr%'
複制
自适應哈希索引(Adaptive Hash Index,AHI)是指 InnoDB 存儲引擎會自動根據通路的頻率和模式來自動地為某些熱點頁建立哈希索引。AHI 是通過緩沖池的 B+ 樹頁構造而來,是以建立的速度很快,而且不需要對整張表建構哈希索引。
在 InnoDB 存儲引擎中,采用異步IO(Asynchronous IO,AIO)的方式來處理磁盤操作。
SHOW VARIABLES LIKE 'innodb_use_native_aio'
複制
InnoDB 存儲引擎還提供了 Flush Neighbor Page(重新整理鄰接頁)的特性。其工作原理為:當重新整理一個髒頁時,InnoDB 存儲引擎會檢測該頁所在區的所有頁,如果是髒頁,那麼一起進行重新整理,這樣做的操作顯而易見,通過 AIO 可以将多個 IO 寫入操作合并為一個 IO 操作。(固态硬碟具有超高的 IOPS)
SHOW VARIABLES LIKE 'innodb_flush_neighbors'
複制