InnoDB存儲引擎的內存管理機制

InnoDB緩衝池是經過LRU算法來管理page的。頻繁使用的page放在LRU列表的前端,最少使用的page在LRU列表的尾端,緩衝池滿了的時候,優先淘汰尾端的page。前端

InnoDB中的LRU結構

InnoDB引擎中page的默認大小爲16KB,InnoDB對傳統的LRU算法作了一些優化。以下圖所示:mysql

innod-LRU

LRU列表被分紅兩部分,midpoint點以前的部分稱爲new列表,以後的部分稱爲old列表,new列表中的頁都是最爲活跌的熱點數據。midpoint的位置經過參數innodb_old_blocks_pct來設置。算法

參數innodb_old_blocks_pct默認值爲37,表示新讀取的page將被插入到LRU列表左側的37%(差很少3/8的位置)。sql

mysql> show variables like 'innodb_old_blocks%';
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| innodb_old_blocks_pct  | 37    |
| innodb_old_blocks_time | 0     |
+------------------------+-------+

爲何不採用傳統的LRU算法?

若直接將讀取到的page放到LRU的首部,那麼某些SQL操做可能會使緩衝池中的page被刷出。常見的這類操做爲索引或數據的掃描操做。這類操做訪問表中的許多頁,而這些頁一般只是在此次查詢中須要,並非活躍數據。若是放入到LRU首部,那麼很是可能將真正的熱點數據從LRU列表中移除,在下一次須要時,InnoDB須要從新訪問磁盤讀取,這樣性能會低下。數據庫

同時,InnoDB進一步引入了另外一個參數來管理LRU列表,這個參數就是innodb_old_blocks_time,用於表示page放到midpoint位置後須要等待多久纔會被加入到LRU列表的new端成爲熱點數據。數據結構

LRU中page的變化

數據庫啓動時,LRU列表是空的,即沒有任何page,這時page都存放在Free列表中。當須要從緩衝池中分頁時,首先從Free列表中查找是否有可用的空閒頁,如有則將page從Free中刪除,放入到LRU中。不然,根據LRU算法,淘汰LRU列表末尾的頁分配給新的頁。dom

當頁從old部分進入到new部分時,此時發生的操做爲page made young。由於innodb_old_blocks_time參數致使page沒有從old移動到new部分稱爲page not made young。能夠經過命令show engine innodb status來觀察LRU列表及Free列表的狀態。性能

----------------------
BUFFER POOL AND MEMORY
----------------------
Total memory allocated 4395630592; in additional pool allocated 0
Dictionary memory allocated 28892957
Buffer pool size   262143
Free buffers       0
Database pages     258559
Old database pages 95424
Modified db pages  36012
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 72342127, not young 0
8.82 youngs/s, 0.00 non-youngs/s
Pages read 72300801, created 339791, written 13639066
8.56 reads/s, 0.35 creates/s, 3.79 writes/s
Buffer pool hit rate 1000 / 1000, young-making rate 0 / 1000 not 0 / 1000
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 258559, unzip_LRU len: 0
I/O sum[459]:cur[1], unzip sum[0]:cur[0]
  • Buffer pool size表示緩衝池共有262143個page,即262143 * 16K,約爲4GB
  • Free buffers表示當前Free列表中page的數量
  • Database pages表示LRU列表中page的數量
  • Old database pages表示LRU列表中old部分的page數量
  • Modified db pages表示的是髒頁(dirty page)的數量
  • Pages made young表示LRU列表中page移動到new部分的次數
  • youngs/s, non-youngs/s表示每秒這兩種操做的次數
  • Buffer pool hit rate表示緩衝池的命中率,該值若小於95%,須要觀察是否全表掃描引發LRU污染
  • LRU len表示LRU中總page數量

能夠看到Free buffers與Database pages的和不等於Buffer pool size,這是由於緩衝池中的頁還會被分配給自適應哈希索引,Lock信息,Insert Buffer等頁,這部分頁不須要LRU算法維護。優化

髒頁(dirty page)

LRU列表中的page被修改後,稱該頁爲髒頁,即緩衝池中的頁和磁盤上的頁的數據產生了不一致。這時InnoDB經過Checkpoint機制將髒頁刷新回磁盤。而Flush列表中的頁即爲髒頁列表。髒頁既存在於LRU列表中,又存在於Flush列表中,兩者互不影響。Modified db pages顯示的就是髒頁的數量。日誌

重作日誌緩衝

InnoDB引擎首先將重作日誌信息先放到重作日誌緩衝區(redo log buffer),而後按必定頻率刷新到重作日誌文件。重作日誌緩衝不須要設置很大,通常每一秒都會刷新redo log buffer,配置的大小隻須要保證每秒產生的事務在這個緩衝區大小以內便可。經過參數innodb_log_buffer_size爲設置:

mysql> show variables like 'innodb_log_buffer%';
+------------------------+----------+
| Variable_name          | Value    |
+------------------------+----------+
| innodb_log_buffer_size | 16777216 |
+------------------------+----------+

在下列狀況下會將重作日誌緩衝中的內容刷新到磁盤重作日誌文件中:

  • Master Thread每一秒中刷新一次
  • 每一個事務提交時會刷新
  • 當重作日誌緩衝區空間小於1/2時

額外內存池

額外的內存池用來對一些數據結構自己的內存進行分配,例如緩衝控制對象(buffer control block)記錄的LRU,鎖,等待等信息。額外的內存池不夠時會從緩衝池中進行申請。所以,在申請了很大的InnoDB緩衝池時,額外的內存池也要適當的調大。經過參數innodb_additional_mem_pool_size來設置大小。查看經過以下命令:

mysql> show variables like '%pool_size';
+---------------------------------+------------+
| Variable_name                   | Value      |
+---------------------------------+------------+
| innodb_additional_mem_pool_size | 67108864   |
| innodb_buffer_pool_size         | 4294967296 |
+---------------------------------+------------+
相關文章
相關標籤/搜索