掰扯下Innodb內存架構之BufferPool

  1. 咱們都知道mysql中的數據最終都會存到磁盤上,而咱們又知道磁盤的讀寫速度和cpu不是在一個數量級上,因此咱們猜想mysql存儲引擎裏必然有緩衝這一律念,本節咱們就好好掰扯掰扯myslq中的緩存.
  2. 先到官網看看,存儲innodb存儲引擎的結構
    image.png
    從上圖咱們能夠看到,INNODB架構,大體分爲內存部分結構和磁盤部分結構,
    而內存部分又有BufferPool,ChangeBuffer,Adaptive Hash Index,LogBuffer等
    .咱們將按照本圖內存部分結構一點一點掰扯每個緩存部分.
    這裏推薦你們沒事多喵喵官網:

14.5.1 Buffer Poolhtml

14.5.2 Change Buffermysql

14.5.3 Adaptive Hash Index算法

14.5.4 Log Buffer
3:首先來看BufferPoolsql

  • 說白了就是內存裏一個最主要的緩存數據,而且在專用服務器上(這裏能夠理解mysql的生產環境) 80%的物理內存都分配給了buffer pool。 可見buffer的重要性。
  • 那數據在buffer裏是怎麼存儲的呢? 在看官方給的架構圖
    image.png
    先不細分析這個結構,大體看了下就是使用了LRU(least recently used 這個你們都很熟悉吧.不熟悉自行補充)算法. 而且把整個列表分了new和old兩部分. 還有一點就是列表裏每一項到底緩存數據的維度是什麼?因此下面將分3個部分介紹 1:buffer pool 緩存的數據維度是什麼? 2:爲何LRU算法還有new和old部分,爲何會這樣涉及? 3:實戰看下buffer pool相關的部分
    1:buffer pool 緩存的數據維度是什麼?
    When room is needed to add a new page to the buffer pool, the least recently used page is evicted and a new page is added to the middle of the list. 從官方這句話,咱們能夠得知每一項都是一頁數據 . 這個後期寫mysql索引文章的時候,會詳細分析爲何會是頁數據爲單位.
    2:爲何LRU算法還有new和old部分,爲何會這樣設計?數據庫

    其實你們想一想只有LRU算法的缺點就知道了. 看下圖

    image.png

    就是隨着新的數據頁進來,列表中的數據會被大量置換出去. 沒有達到緩存的目的. 其實官方也介紹了哪些狀況下會出現這種狀況[見下圖].
    image.png
    說白了,全表掃描,什麼mysqldump操做,select語句沒有where條件,都會把大量數據放進buffer bool,即時這些數據並非熱點數據, 但同時還會把熱點數據給排擠出去.
    那增長了new和old部分,當出現上面操做,又是怎樣保護熱點數據呢?
    image.png
    可從上圖看出,新讀入的數據都放在old列表,而且不會替換掉new列表中的熱點數據. 那問題來了,何時old列表中數據會進入new列表呢?
    實際上是進入buffer pool的數據,能被真正讀取到, 並停留必定時間窗口,纔會進入new列表 [有點像jvm內存分代,多大年齡能夠進入老年代].緩存

    其實真實的狀況是: 首先mysql會預讀數據 [局部性原理,你們能夠自行了解] 另外加上上面說的全表掃描 mysqldump等. 這兩種狀況, 使進入的buffer pool中的數據並不必定被讀到, 因此不能直接把熱點數據給置換掉,才弄出來new列表和old列表,而且old列表的數據被訪問到,且經歷過T時間[時間窗口] 纔會進入new列表.服務器

    3:實戰看下buffer pool相關的部分數據結構

  • 先本能到看下數據庫關於buffer pool提供了哪些參數

窗口執行 show variables like '%buffer_pool%';
image.png
好像看不太懂,仍是從buffer pool的數據結構反推應該有哪些配置吧.架構

  • 首先咱們應該想到的是 一個mysql實例容許有幾個buffer pool. 看上面架構圖,好像只有一個,經過翻查資料,從INNODB1.0.X以後,容許有多個緩衝池實例. 因此找下確定有緩衝池實例的配置.
    沒錯 innodb_buffer_pool_instances=1 默認一個.
    另外 忽然扒到information_schema 裏有INNODB_BUFFER_POOL_STATS表. 猜想從裏能查看緩衝池狀態信息. 先看看在說.
    image.png

能夠看到有好多字段, 但有個POOL_ID=0 可見我本地就一個緩衝池.jvm

  • 其次就是緩衝池大小
    沒錯 innodb_buffer_pool_size=134217728
  • 有了大小了,咱們知道緩衝池分別new列表和old列表 因此確定有控制分割比例的配置
    沒錯 innodb_old_blocks_pct=37 官網給的是3/8處. 可見這個是個經驗值,或者有什麼破定律使這個值最合適. 不廢話,去官網看看咋解釋的.

image.png
innodb_old_blocks_pct表明old列表的大小,範圍[5,95] 其餘本身到官網看吧.

  • 不過從上圖又發現時間窗口的配置了

innodb_old_blocks_time=1000 默認1s

綜合innodb_old_blocks_pct和innodb_old_blocks_time 有兩種狀況
若是業務中常常出現表掃描, 這時候就該把innodb_old_blocks_pct調小, 把innodb_old_blocks_time調大,避免不少預讀的數據進入緩衝區.
若是業務中沒有大量的表掃描. 這時候就該把innodb_old_blocks_pct調大,把innodb_old_blocks_time減少,讓熱點數據儘快進入new列表.減小磁盤io,提升性能.

  • 如今咱們宏觀看下整個buffer pool, 咱們能不能對他了解的更多.
    有多少個buffer pool 咱們已經知道. 大小咱們也知道. new列表和old列表大小咱們也知道. 如今惟一不知道的是buffer pool裏緩存了多少頁數據? 從old列表跑到new列表的量,頻率等?
    還有個疑問點,上面POOL_SIZE=8191 和 innodb_buffer_pool_size=134217728 不是一個概念? 那POOL_SIZE=8191是什麼概念呢?
    終於又從information_schema中發現兩張表:
    image.png

INNODB_BUFFER_PAGE
INNODB_BUFFER_PAGE_LRU
先看第一張表:INNODB_BUFFER_PAGE
image.png 如今明白了 其實就是緩衝池中的全部的頁信息.
在來看第二張表INNODB_BUFFER_PAGE_LRU
image.png
實際上是LRU列表中的頁信息. 從這裏咱們能夠得出,BUFFER POOL 中不只僅只有一個LRU列表,還有其餘緩存信息.

  • 那LRU列表中 old到new這些頻率怎麼看? 命中率怎麼看? 其實上面有個圖已經有這些信息了,在來看看.
    image.png

HIT_RATE:表示命中率 不用說,越高越好.
PAGES_MADE_YONG: 這個是從old列表到new列表的數量。

另外咱們發現: FREE_BUFFERS: 7704

DATABASE_PAGES: 487
        POOL_SIZE: 8191

7704+487=8191; 可見buffer_pool 中除來一個lru列表[目前是DATABASE_PAGES] 還有一個FREE_BUFFERS緩存. 其餘的緩存咱們下一次在一一分析.

相關文章
相關標籤/搜索