InnoDB 存儲引擎

一、InnoDB 體系架構

InnoDB 存儲引擎

InnoDB 存儲引擎有多個內存塊,可以認為這些內存塊組成了一個大的內存池,負責如下工作:

  • 維護所有進程/線程需要訪問的多個內部數據結構。
  • 緩存磁盤上的數據,方便快速的讀取,同時對磁盤文件的數據修改之前在這裡進行緩存。
  • 重做日誌(redo log)緩衝。

後臺線程的主要作用是負責刷新內存池中的數據,保證緩衝池中的內存緩存的是最近的數據。同時將已修改的數據文件刷新到磁盤文件,同時保證在數據庫發生異常的情況下 InnoDB 能恢復到正常運行狀態。

通過 SHOW ENGINE INNODB STATUS 可以觀察到 INNODB 存儲引擎的運行情況。

<code>SHOW ENGINE INNODB STATUS/<code>

二、內存池

InnoDB 存儲引擎


緩衝池簡單來說就是一塊內存區域,通過內存的速度來彌補磁盤速度較慢對數據庫性能的影響。緩衝池的大小直接影響著數據庫的整體性能,可以通過配置參數 innodb_buffer_pool_size 來設置。


<code>SHOW VARIABLES LIKE 'innodb_buffer_pool_size'/<code>

並且 InnoDB 允許有多個緩存池實例,每個 PAGE 根據哈希值平均分配到不同緩衝池實例中,這樣做的好處是減少數據庫內部的資源競爭,增加數據庫的併發處理能力,可以通過配置參數 innodb_buffer_pool_instances 來設置。

<code>SHOW VARIABLES LIKE 'innodb_buffer_pool_instances'/<code>

通常來說,數據庫中的緩存池是通過 LRU(Lastest Recent Used,最近最少使用)算法來進行管理的,緩存池的默認單位是 "頁",一頁默認 16 KB。

從 InnoDB 1.2 版本開始,可以通過 INNODB_BUFFER_POOL_STATS 來觀察緩存池的運行狀態。

<code>SELECT 
 POOL_ID,
 HIT_RATE '緩存池的命中率',
 PAGES_MADE_YOUNG AS '緩存池 old 部分加入到 new 部分的次數', 
 PAGES_NOT_MADE_YOUNG '緩存池 new 部分加入到 old 部分的次數'
FROM information_schema.INNODB_BUFFER_POOL_STATS/<code>

重做日誌緩存是用來存放重做日誌信息的,一般不需要設置得過大,因為一般情況下每一秒鐘都會將重做日誌緩存刷新到日誌文件,一般設置 8MB 就足以滿足絕大部分得應用,可通過 INNODB_LOG_BUFFER_SIZE 參數控制。

<code>SHOW VARIABLES LIKE 'INNODB_LOG_BUFFER_SIZE'/<code>

當前事務數據庫系統普遍都採用了 WriteAhead Log 策略,即當事務提交時,先寫重做日誌,再修改頁。因此,重做日誌的作用是對數據庫系統中的數據進行恢復(當數據庫系統異常宕機的時候)。

額外內存池是用來分配一些數據結構本身的內存,例如緩衝池中的幀緩存(frame buffer)、緩衝控制對象(innodb_buffer_pool)。

三、後臺線程

Master Thread 是一個非常核心的後臺線程,主要負責將緩存池中的數據異步刷新到磁盤,保證數據的一致性,包括髒頁的刷新、合併插入緩存(INSERT BUFFER)、UNDO 頁的回收等。

IO Thread 的工作主要是負責 IO 請求的回調處理(InnoDB 存儲引擎中大量的使用了 AIO 來處理寫 IO 請求)。

<code>SHOW VARIABLES LIKE 'INNODB_%io_threads'/<code>

PurgeThread 是在 InnoDB 1.1.x 版本中引入的。用來回收已經使用並分配的 undo 頁以減輕 Master Thread 的工作量 ,因為事務被提交後,其所使用的 undolog 可能不再需要。

<code>SHOW VARIABLES LIKE 'INNODB_purge_threads'/<code>

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 中找到該頁的一個副本,將其複製到表空間文件,再應用重做日誌。

<code>SHOW GLOBAL STATUS LIKE 'INNODB_dblwr%'/<code>
InnoDB 存儲引擎

自適應哈希索引(Adaptive Hash Index,AHI)是指 InnoDB 存儲引擎會自動根據訪問的頻率和模式來自動地為某些熱點頁建立哈希索引。AHI 是通過緩衝池的 B+ 樹頁構造而來,因此建立的速度很快,而且不需要對整張表構建哈希索引。

在 InnoDB 存儲引擎中,採用異步IO(Asynchronous IO,AIO)的方式來處理磁盤操作。

<code>SHOW VARIABLES LIKE 'innodb_use_native_aio'/<code>

InnoDB 存儲引擎還提供了 Flush Neighbor Page(刷新鄰接頁)的特性。其工作原理為:當刷新一個髒頁時,InnoDB 存儲引擎會檢測該頁所在區的所有頁,如果是髒頁,那麼一起進行刷新,這樣做的操作顯而易見,通過 AIO 可以將多個 IO 寫入操作合併為一個 IO 操作。(固態硬盤具有超高的 IOPS)

<code>SHOW VARIABLES LIKE 'innodb_flush_neighbors'/<code>


分享到:


相關文章: