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

詳細了解 InnoDB 內存結構及其原理

存儲 存儲軟件
聊了一下MySQL和InnoDB的日志,和兩次寫,總的來說算是一個入門級別的介紹,這篇文章就來詳細介紹一下InnoDB的內存結構。

 [[392749]]

之前寫過一篇文章「簡單了解InnoDB原理」,現在回過頭看,其實里面只是把緩沖池(Buffer Pool),重做日志緩沖(Redo Log Buffer)、插入緩沖(Insert Buffer)和自適應哈希索引(Adaptive Hash Index)等概念簡單的介紹了一下。

除此之外還聊了一下MySQL和InnoDB的日志,和兩次寫,總的來說算是一個入門級別的介紹,這篇文章就來詳細介紹一下InnoDB的內存結構。

InnoDB內存結構

其大致結構如下圖。

InnoDB內存的兩個主要區域分別為Buffer Pool和Log Buffer,此處的Log Buffer目前是用于緩存Redo Log。而Buffer Pool則是MySQL或者說InnoDB中,十分重要、核心的一部分,位于主存。這也是為什么其訪問數據的效率高,你可以暫時把它理解成Redis那樣的內存數據庫,因為我們更新和新增當然它不是,只是這樣會更加方便我們理解。

Buffer Pool

通常來說,宿主機80%的內存都應該分配給Buffer Pool,因為Buffer Pool越大,其能緩存的數據就更多,更多的操作都會發生在內存,從而達到提升效率的目的。

由于其存儲的數據類型和數據量非常多,Buffer Pool存儲的時候一定會按照某些結構去存儲,并且做了某些處理。否則獲取的時候除了遍歷所有數據之外,沒有其他的捷徑,這樣的低效率操作肯定是無法支撐MySQL的高性能的。

因此,Buffer Pool被分成了很多頁,這在之前的文章中也有講過,這里不再贅述。每頁可以存放很多數據,剛剛也提到了,InnoDB一定是對數據做了某些操作。

InnoDB使用了鏈表來組織頁和頁中存儲的數據,頁與頁之間形成了雙向鏈表,這樣可以方便的從當前頁跳到下一頁,同時使用LRU(Least Recently Used)算法去淘汰那些不經常使用的數據。

同時,每頁中的數據也通過單向鏈表進行鏈接。因為這些數據是分散到Buffer Pool中的,單向鏈表將這些分散的內存給連接了起來。

Log Buffer

Log Buffer用來存儲那些即將被刷入到磁盤文件中的日志,例如Redo Log,該區域也是InnoDB內存的重要組成部分。Log Buffer的默認值為16M,如果我們需要進行調整的話,可以通過配置參數innodb_log_buffer_size來進行調整。

當Log Buffer如果較大,就可以存儲更多的Redo Log,這樣一來在事務提交之前我們就不需要將Redo Log刷入磁盤,只需要丟到Log Buffer中去即可。因此較大的Log Buffer就可以更好的支持較大的事務運行;同理,如果有事務會大量的更新、插入或者刪除行,那么適當的增大Log Buffer的大小,也可以有效的減少部分磁盤I/O操作。

至于Log Buffer中的數據刷入到磁盤的頻率,則可以通過參數innodb_flush_log_at_trx_commit來決定。

Buffer Pool的LRU算法

了解完了InnoDB的內存結構之后,我們來仔細看看Buffer Pool的LRU算法是如何實現將最近沒有使用過的數據給過期的。

原生LRU

首先明確一點,此處的LRU算法和我們傳統的LRU算法有一定的區別。為什么呢?因為實際生產環境中會存在全表掃描的情況,如果數據量較大,可能會將Buffer Pool中存下來的熱點數據給全部替換出去,而這樣就會導致該段時間MySQL性能斷崖式下跌。

對于這種情況,MySQL有一個專用名詞叫緩沖池污染。所以MySQL對LRU算法做了優化。

優化后的LRU

優化之后的鏈表被分成了兩個部分,分別是 New Sublist 和 Old Sublist,其分別占用了 Buffer Pool 的3/4和1/4。

鏈表的前3/4,也就是 New Sublist 存放的是訪問較為頻繁的頁,而后1/4也就是 Old Sublist 則是反問的不那么頻繁的頁。Old Sublist中的數據,會在后續Buffer Pool剩余空間不足、或者有新的頁加入時被移除掉。

了解了鏈表的整體構造和組成之后,我們就以新頁被加入到鏈表為起點,把整體流程走一遍。首先,一個新頁被放入到Buffer Pool之后,會被插入到鏈表中 New Sublist 和 Old Sublist 相交的位置,該位置叫MidPoint。

該鏈表存儲的數據來源有兩部分,分別是:

  • MySQL的預讀線程預先加載的數據
  • 用戶的操作,例如Query查詢

默認情況下,由用戶操作影響而進入到Buffer Pool中的數據,會被立即放到鏈表的最前端,也就是 New Sublist 的 Head 部分。但如果是MySQL啟動時預加載的數據,則會放入MidPoint中,如果這部分數據被用戶訪問過之后,才會放到鏈表的最前端。

這樣一來,雖然這些頁數據在鏈表中了,但是由于沒有被訪問過,就會被移動到后1/4的 Old Sublist中去,直到被清理掉。

優化Buffer Pool的配置

在實際的生產環境中,我們可以通過變更某些設置,來提升Buffer Pool運行的性能。

  • 例如,我們可以分配盡量多的內存給Buffer Pool,如此就可以緩存更多的數據在內存中
  • 當前有足夠的內存時,就可以搞多個Buffer Pool實例,減少并發操作所帶來的數據競爭
  • 當我們可以預測到即將到來的大量請求時,我們可以手動的執行這部分數據的預讀請求
  • 我們還可以控制Buffer Pool刷數據到磁盤的頻率,以根據當前MySQL的負載動態調整

那我們怎么知道當前運行的 MySQL 中 Buffer Pool 的狀態呢?我們可以通過命令show engine innodb status來查看。這個命令是看 InnoDB 整體的狀態的, Buffer Pool 相關的監控指標包含在了其中,在Buffer Pool And Memory模塊中。

樣例如下。

  1. ---------------------- 
  2. BUFFER POOL AND MEMORY 
  3. ---------------------- 
  4. Total large memory allocated 137428992 
  5. Dictionary memory allocated 972752 
  6. Buffer pool size   8191 
  7. Free buffers       4596 
  8. Database pages     3585 
  9. Old database pages 1303 
  10. Modified db pages  0 
  11. Pending reads      0 
  12. Pending writes: LRU 0, flush list 0, single page 0 
  13. Pages made young 1171, not young 0 
  14. 0.00 youngs/s, 0.00 non-youngs/s 
  15. Pages read 655, created 7139, written 173255 
  16. 0.00 reads/s, 0.00 creates/s, 0.00 writes/s 
  17. No buffer pool page gets since the last printout 
  18. Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s 
  19. LRU len: 3585, unzip_LRU len: 0 
  20. I/O sum[0]:cur[0], unzip sum[0]:cur[0] 

解釋一些關鍵的指標所代表的含義:

  • Total memory allocated:分配給 Buffer Pool 的總內存
  • Dictionary memory allocated:分配給 InnoDB 數據字典的總內存
  • Buffer pool size:分配給 Buffer Pool 中頁的內存大小
  • Free buffers:分配給 Buffer Pool 中 Free List 的內存大小
  • Database pages:分配給 LRU 鏈表的內存大小
  • Old database pages:分配給 LRU 子鏈表的內存大小
  • Modified db pages:當前Buffer Pook中被更新的頁的數量
  • Pending reads:當前等待讀入 Buffer Pool 的頁的數量
  • Pending writes LRU:當前在 LRU 鏈表中等待被刷入磁盤的臟頁數量

都是些很常規的配置項,你可能會比較好奇什么是 Free List。

Free List 中存放的都是未被使用的頁。因為MySQL啟動的時候,InnoDB 會預先申請一部分頁。如果當前頁還未被使用,就會被保存在 Free List 中。

知道了 Free List,那么你也應該知道 Flush List,里面保存的是所有的臟頁,都是被更改后需要刷入到磁盤的。

自適應哈希索引

自適應哈希索引(Adaptive Hash Index)是配合Buffer Pool工作的一個功能。自適應哈希索引使得MySQL的性能更加接近于內存服務器。

如果要啟用自適應哈希索引,可以通過更改配置innodb_adaptive_hash_index來開啟。如果不想啟用,也可以在啟動的時候,通過命令行參數--skip-innodb-adaptive-hash-index來關閉。

自適應哈希索引是根據索引Key的前綴來構建的,InnoDB 有自己的監控索引的機制,當其檢測到為當前某個索引頁建立哈希索引能夠提升效率時,就會創建對應的哈希索引。如果某張表數據量很少,其數據全部都在Buffer Pool中,那么此時自適應哈希索引就會變成我們所熟悉的指針這樣一個角色。

當然,創建、維護自適應哈希索引是會帶來一定的開銷的,但是比起其帶來的性能上的提升,這點開銷可以直接忽略不計。但是,是否要開啟自適應哈希索引還是需要看具體的業務情況的,例如當我們的業務特征是有大量的并發Join查詢,此時訪問自適應哈希索引被產生競爭。并且如果業務還使用了LIKE或者%等通配符,根本就不會用到哈希索引,那么此時自適應哈希索引反而變成了系統的負擔。

所以,為了盡可能的減少并發情況下帶來的競爭,InnoDB對自適應哈希索引進行了分區,每個索引都被綁定到了一個特定的分區,而每個分區都由單獨的鎖進行保護。其實通俗點理解,就是降低了鎖的粒度。分區的數量我們可以通過配置innodb_adaptive_hash_index_parts來改變,其可配置的區間范圍為[8, 512]。

Change Buffer

聊完了 Buffer Pool 中索引相關,剩下的就是 Change Buffer 了。Change Buffer是一塊比較特殊的區域,其作用是用于存儲那些當前不在 Buffer Pool 中的但是又被修改過的二級索引。

用流程來描述一下就是,當我們更新了非聚簇索引(二級索引)的數據時,此時應該是直接將其在Buffer Pool中的對應數據更新了即可,但是不湊巧的是,當前二級索引不在 Buffer Pool 中,此時將其從磁盤拉取到 Buffer Pool 中的話,并不是最優的解,因為該二級索引可能之后根本就不會被用到,那么剛剛昂貴的磁盤I/O操作就白費了。

所以,我們需要這么一個地方,來暫存對這些二級索引所做的改動。當被緩存的二級索引頁被其他的請求加載到了Buffer Pool 中之后,就會將 Change Buffer 中緩存的數據合并到 Buffer Pool 中去。

當然,Change Buffer也不是沒有缺點。當 Change Buffer 中有很多的數據時,全部合并到Buffer Pool可能會花上幾個小時的時間,并且在合并的期間,磁盤的I/O操作會比較頻繁,從而導致部分的CPU資源被占用。

那你可能會問,難道只有被緩存的頁加載到了 Buffer Pool 才會觸發合并操作嗎?那要是它一直沒有被加載進來,Change Buffer 不就被撐爆了?很顯然,InnoDB在設計的時候考慮到了這個點。除了對應的頁加載,提交事務、服務停機、服務重啟都會觸發合并。

責任編輯:武曉燕 來源: SH的全棧筆記
相關推薦

2009-07-06 16:05:50

JSP特點

2022-03-08 08:44:13

偏向鎖Java內置鎖

2010-04-16 11:08:23

2010-11-16 09:55:12

Oracle分區索引

2011-07-28 10:40:40

Cocoa KVO

2011-06-07 11:21:04

JSP隱含對象

2021-07-22 06:08:43

SQL.js關系數據庫數據庫

2011-08-25 15:10:49

LUAWindows環境配置

2011-07-01 14:34:02

Thread Affinity 信號

2010-10-25 11:51:05

Oracle單行字符串

2010-10-21 15:26:35

SQL Server字

2010-11-12 14:29:46

Sql Server創

2018-11-27 15:55:21

TCP通訊協議

2010-09-27 09:31:42

JVM內存結構

2023-10-30 13:31:22

Springboot工具Java

2021-06-12 07:38:21

Linkerd 2.Service Mes微服務

2022-09-21 18:06:10

Python內存管理

2009-04-28 13:48:09

2019-09-18 08:31:47

數據結構設計

2019-11-04 12:51:48

mysql數據庫nnodb
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 精品国产1区2区3区 在线国产视频 | 久久久久国产精品免费免费搜索 | 高清免费av| 97久久久久久 | 日本中出视频 | 国产99久久精品一区二区300 | 一级无毛片 | 超碰97人人人人人蜜桃 | 成人国产精品久久 | 亚洲高清一区二区三区 | 欧美性猛交一区二区三区精品 | 伊人精品在线 | 日韩精品色网 | www.xxxx欧美| 亚洲一区二区三区福利 | 中文字幕亚洲欧美日韩在线不卡 | 中文字幕亚洲一区 | 亚洲在线| 亚洲午夜在线 | 成人国产在线观看 | 91精品欧美久久久久久久 | 久久久久久亚洲精品 | 欧美h版 | 免费看色| 久久国产精品网站 | av看片网站 | 国产一区二区在线免费播放 | 999www视频免费观看 | 国产精品自产拍 | 91久久久久 | 中文字幕国产精品 | 中文字幕免费在线 | 91麻豆精品国产91久久久久久 | 拍戏被cao翻了h承欢 | 国产激情偷乱视频一区二区三区 | 成人精品久久日伦片大全免费 | av在线影院 | 国产日韩欧美精品 | 999久久精品| 久久久久久久一区二区三区 | 日韩国产一区二区 |