成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

面試官:能說一說MySQL緩存池嗎?

數據庫 MySQL
今天來聊一聊 Mysql 緩存池原理。希望能幫助到你。

[[374177]]

 大家好,我是狂聊君。

今天來聊一聊 Mysql 緩存池原理。

提綱附上,話不多說,直接干貨。


前言

面試官:同學,你能說說Mysql 緩存池嗎?

狂聊君:啊,這么難嗎,容我組織一下語言。(內心OS:這TM還不簡單?我能給你扯半小時!)

面試官:可以,給你一分鐘時間想一想吧。

....一分鐘后....

狂聊君:我準備好了,你可聽好,我要開始表演了。

為什么要有緩存池?

Mysql 的 innodb 存儲引擎是基于磁盤存儲的,并且是按照頁的方式進行管理的。

在數據庫系統中,CPU 速度與磁盤速度之間的差距是非常大的,為了最大可能的彌補之間的差距,提出了緩存池的概念。

所以緩存池,簡單來說就是一塊「內存區域,通過內存的速度來彌補磁盤速度較慢,導致對數據庫造成性能的影響。

緩存池的基本原理

「讀操作」:

在數據庫中進行讀取頁的操作,首先把從磁盤讀到的頁存放在緩存池中,下一次讀取相同的頁時,首先判斷該頁是不是在緩存池中。

若在,稱該頁在緩存池中被命中,則直接讀取該頁,否則,還是去讀取磁盤上的頁。

「寫操作」:

對于數據庫中頁的修改操作,首先修改在緩存池中的頁,然后在以一定的頻率刷新到磁盤,并不是每次頁發生改變就刷新回磁盤,而是通過 checkpoint 的機制把頁刷新回磁盤。

可以看到,無論是讀操作還是寫操縱,都是對緩存池進行操作,而不是直接對磁盤進行操縱。

緩存池結構

Buffer Pool 是一片連續的內存空間,innodb 存儲引擎是通過頁的方式對這塊內存進行管理的。

緩存池的結構如下圖:


可以看到緩存池中包括數據頁、索引頁、插入緩存、自適應哈希索引、鎖信息、數據字段。

其中數據頁和索引頁會用掉多數內存。

「但是,innodb 是如何管理緩存池中的這么多頁呢?」

為了更好的管理這些緩存的頁,innodb 為每一個緩存頁都創建了一些所謂的控制信息,這些控制信息包括該頁所屬的:

  • 表空間編號(sapce id)
  • 頁號(page numeber)
  • 頁在 buffer Pool 的地址
  • 一些鎖信息以及 LSN 信息日志序列號
  • 其他控制信息

每個緩存頁對應的控制信息占用的內存大小是相同的,我們把每個頁對應的控制信息占用的一塊內存稱為一個「控制塊」

「控制塊」和緩存頁是一一對應的,它們都被存放到 Buffer Pool 中,其中控制塊被存放到 Buffer Pool 的前邊,緩存頁被存放到 Buffer Pool 的后邊。

Buffer Pool 對應的內存空間示意圖:


緩存池參數設置

  • innodb_buffer_pool_size:緩存池的大小最多應設置為物理內存的 80%
  • innodb_buffer_pool_instance:設置有多少個緩存池,通常建議把緩存池個數設置為 CPU 的個數,多個緩存池可以減少數據庫內部的資源競爭,增加數據庫并發訪問的能力
  • innodb_old_blocks_pct:老生代占整個 LRU 的鏈長比例,默認是 3:7
  • innodb_old_blocks_time:老生代停留時間窗口,單位是毫秒,默認是 1000,即同時滿足“被訪問”與“在老生代停留時間超過 1 秒”兩個條件,才會被插入到新生代頭部

緩存池管理

「管理緩存池依賴的鏈表結構」:

Free 鏈表

當啟動 Mysql 服務器的時候,需要完成對 Buffer Pool 的初始化過程,即分配 Buffer Pool 的內存空間,把它劃分為若干對控制塊和緩存頁,但是此時并沒有真正的磁盤頁被緩存到 Buffer Pool 中,之后隨著程序的運行,會不斷的有磁盤上的頁被緩存到 Buffer Pool 中。

在使用過程中,為了記錄哪些緩存頁是可用的,我們把所有空閑的頁包裝成一個節點組成一個鏈表,這個鏈表可以稱作為 Free 鏈表(空閑鏈表)。因為剛剛完成初始化的 Buffer Pool 中所有的緩存頁都是空閑的,所以每一個緩存頁都會被加入到 Free 鏈表中。

為了方便管理 Free 鏈表,特意為這個鏈表定義了一些「控制信息」,里面包含鏈表的頭節點地址,尾節點地址,以及當前鏈表中節點的數量等信息。

另外會在每個 Free 鏈表的節點中都記錄了某個「緩存頁控制塊」的地址,而每個「緩存頁控制塊」都記錄著對應的「緩存頁地址」,所以相當于每個 Free 鏈表節點都對應一個空閑的緩存頁。

給大家畫了個結構圖:


這圖怎么樣,這下能看的懂了吧!

2、Lru 鏈表

Lru 鏈表用來管理已經讀取的頁,當數據庫剛啟動時,Lru 鏈表是空的,此時頁也都放在 Free 列表中,當需要讀取數據時,會從 Free 鏈表中申請一個頁,把從放入到磁盤讀取的數據放入到申請的頁中,這個頁的集合叫做 Lru 鏈表。

3、Flush 鏈表

Flush 鏈表用來管理被修改的頁,Buffer Pool 中被修改的頁也被稱之為「臟頁」,臟頁既存在于 Lru 鏈表中,也存在于 Flush 鏈表中,Flush 鏈表中存的是一個指向 Lru 鏈表中具體數據的指針。

因此只有 Lru 鏈表中的頁第一次被修改時,對應的指針才會存入到 Flush 中,若之后再修改這個頁,則是直接更新 Lru 鏈表中的頁對應的數據。

這三者之間是這么個關系:


讀操作

Buffer Pool 一個最主要的功能是「加速讀」。加速讀是當需要訪問一個數據頁面的時候,如果這個頁面已經在緩存池中,那么就不再需要訪問磁盤,直接從緩沖池中就能獲取這個頁面的內容。當我們需要訪問某個頁中的數據時,就會把該頁加載到 Buffer Pool 中,如果該頁已經在 Buffer Pool 中的話直接使用就可以了。

問題:那么如何快速查找在 Buffer Pool 中的頁呢?

為了避免查詢數據頁時掃描 Lru,其實是根據表空間號 + 頁號來定位一個頁的,也就相當于表空間號 + 頁號是一個 key,緩存頁就是對應的 value。用表空間號 + 頁號作為 key,緩存頁作為 value 創建一個哈希表,在需要訪問某個頁的數據時,先從哈希表中根據表空間號 + 頁號看看有沒有對應的緩存頁。

如果有,直接使用該緩存頁就好。

如果沒有,那就從 Free 鏈表中選一個空閑的緩存頁,然后把磁盤中對應的頁加載到該緩存頁的位置。每當需要從磁盤中加載一個頁到 Buffer Pool 中時,就從 Free 鏈表中取一個空閑的緩存頁,并且把該緩存頁對應的控制塊的信息填上,然后把該緩存頁對應的 Free 鏈表節點從鏈表中移除,表示該緩存頁已經被使用了,并且把該頁寫入 Lru 鏈表。

在初始化的時候,Buffer pool 中所有的頁都是空閑頁,需要讀數據時,就會從 Free 鏈表中申請頁,但是物理內存不可能無限增大,數據庫的數據卻是在不停增大的,所以 Free 鏈表的頁是會用完的。

因此需要考慮把已經緩存的頁從 Buffer pool 中刪除一部分,進而需要考慮如何刪除及刪除哪些已經緩存的頁。假設一共訪問了 n 次頁,那么被訪問的頁在緩存中的次數除以 n 就是緩存命中率,緩存命中率越高,和磁盤的 IO 交互也就越少 。

為了提高緩存命中率,InnoDB 在傳統 Lru 算法的基礎上做了優化,解決了兩個問題:1、預讀失效 2、緩存池污染

寫操作

Buffer pool 另一個主要的功能是「加速寫」,即當需要修改一個頁面的時候,先將這個頁面在緩沖池中進行修改,記下相關的重做日志,這個頁面的修改就算已經完成了。

被修改的頁面真正刷新到磁盤,這個是后臺刷新線程來完成的。前面頁面更新是在緩存池中先進行的,那它就和磁盤上的頁不一致了,這樣的緩存頁被稱為臟頁(dirty page)。

問題:這些被修改的頁面什么時候刷新到磁盤?以什么樣的順序刷新到磁盤?

最簡單的做法就是每發生一次修改就立即同步到磁盤上對應的頁上,但是頻繁的往磁盤中寫數據會嚴重的影響程序的性能。所以每次修改緩存頁后,不能立即把修改同步到磁盤上,而是在未來的某個時間點進行同步,由后臺刷新線程依次刷新到磁盤,實現修改落地到磁盤。

但是如果不立即同步到磁盤的話,那之后再同步的時候如何判斷 Buffer Pool 中哪些頁是臟頁,哪些頁從來沒被修改過呢?

InnoDB 并沒有一次性把所有的緩存頁都同步到磁盤上,InnoDB 創建一個存儲臟頁的鏈表,凡是在 Lru 鏈表中被修改過的頁都需要加入這個鏈表中,因為這個鏈表中的頁都是需要被刷新到磁盤上的,所以這個鏈表也叫 Flush 鏈表,鏈表的構造和 Free 鏈表一致。

這里的臟頁修改指的此頁被加載進 Buffer Pool 后第一次被修改,只有第一次被修改時才需要加入 Flush 鏈表,對于已經存在在 Flush 鏈表中的頁,如果這個頁被再次修改就不會再放到 Flush 鏈表。

需要注意,臟頁數據實際還在 Lru 鏈表中,而 Flush 鏈表中的臟頁記錄只是通過指針指向 Lru 鏈表中的臟頁。并且在 Flush 鏈表中的臟頁是根據 oldest_lsn(這個值表示這個頁第一次被更改時的 lsn 號,對應值 oldest_modification,每個頁頭部記錄)進行排序刷新到磁盤的,值越小表示要最先被刷新,避免數據不一致。

 

責任編輯:姜華 來源: 狂聊Java
相關推薦

2021-07-31 22:20:00

線程池系統參數

2024-02-27 00:10:06

語言Javascript

2021-06-27 21:10:12

Linux 進程控制

2011-07-26 09:04:44

MySQL Repli數據庫負載均衡

2023-09-12 14:56:13

MyBatis緩存機制

2025-03-10 07:05:07

2020-10-30 10:38:50

Python開發語法

2023-10-26 00:41:46

臟讀數據幻讀

2015-10-23 11:40:08

SaaS應用開發

2023-12-29 10:28:24

SPIJava靈活性

2011-07-25 13:34:08

ORACLEFLASHBACK T

2024-03-12 10:44:42

2022-12-05 08:12:31

net/http庫http連接池

2011-07-25 17:38:32

數據存儲一致性模型

2018-01-17 15:15:22

虛擬化IO半虛擬化

2023-12-29 13:45:00

2023-12-13 13:31:00

useEffect對象瀏覽器

2024-02-20 14:10:55

系統緩存冗余

2024-02-21 16:42:00

2021-07-28 10:08:19

類加載代碼塊面試
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美一级在线视频 | 久久久青草婷婷精品综合日韩 | www.天天操.com | 日韩欧美中文在线 | 久久精品日产第一区二区三区 | 亚洲在线免费观看 | 黄色毛片免费看 | 亚洲欧美视频在线观看 | 福利精品 | 日本黄色的视频 | 美国a级毛片免费视频 | 91麻豆精品国产91久久久久久久久 | 久草新在线 | 成人精品久久久 | 在线午夜 | 亚洲一区二区在线电影 | 欧美成人激情视频 | 日本黄色一级视频 | 一区二区在线观看av | 国产婷婷在线视频 | 久久久久一区 | 国产91精品久久久久久久网曝门 | 国产精品99久久久精品免费观看 | 久久久久久久久久久丰满 | 久久国产精品72免费观看 | 欧美日韩在线看 | 刘亦菲国产毛片bd | 久久成人国产精品 | 国产一区二区不卡 | 色综合视频 | 国产99久久久国产精品下药 | 久久国产成人 | 午夜看电影在线观看 | 成人精品一区二区 | 欧美精品在线一区 | 黄色网址在线免费观看 | 久久日本 | 精品一区二区三区在线观看 | 国产特一级黄色片 | 欧美午夜精品久久久久免费视 | 久久精品99国产精品日本 |