前言
??本來只是想了解下redo、undo log的機(jī)制盗胀,但發(fā)現(xiàn)好像牽扯挺多知識點(diǎn),就寫了這篇文章記錄下票灰。。米间。
InnoDB 架構(gòu)
本文分析的mysql版本為8.0
一 InnoDB 內(nèi)存結(jié)構(gòu)
1.1 Buffer pool
??Buffer pool(下文簡稱BP) 是在主內(nèi)存中的一塊區(qū)域膘侮,用于在訪問時緩存表和索引數(shù)據(jù)屈糊。它可以直接從內(nèi)存處理數(shù)據(jù),因此處理速度非城砹耍快。
??為了提高大容量讀取操作的效率雕薪,BP被分成可以容納多行的Page(默認(rèn)16K)。BP的底層數(shù)據(jù)結(jié)構(gòu)是鏈表所袁,以此管理Page。
1.1.1 Buffer Pool LRU
??BP的LRU是一種變體燥爷。BP插入數(shù)據(jù)時懦窘,采用了中間策略(midpoint insertion strategy)稚配。中間策略將BP視為兩個子列表:
new sublist : 存放最近訪問的子列表
old sublist : 存放最近訪問較少的子列表
LRU算法主要的操作如下:
- 默認(rèn)將3/8的BP空間分配給old sublist
- 規(guī)定midpoint為
new sublist
的tail 與old sublist
的head交界處 - InnoDB讀取Page到BP時畅涂,插入到midpoint(old sublist的頭部)道川。Page被讀取有兩種情況:
- 用戶的sql查詢
- InnoDB的預(yù)讀操作
- 當(dāng)訪問old sublist的Page時,會將其移到new sublist的head,實(shí)際上幾乎所有的read Page操作都會將其移動到new sublist的head冒萄。除了預(yù)讀的Page的情況,預(yù)讀后如果一直沒其他的讀操作,該P(yáng)age最終會從tail剔除
- 隨著數(shù)據(jù)庫的運(yùn)行,一直沒有被訪問的page會被移向tail尊流,最終被剔除
1.1.2 Making the Buffer Pool Scan Resistant
默認(rèn)情況下,會出現(xiàn)以下兩種case
- 因表掃描奠旺,大量數(shù)據(jù)讀入BP施流,但這數(shù)據(jù)之后不再被使用
- 由預(yù)讀加載然后僅訪問一次的Page移動到新列表的頭部
這兩種情況可以將經(jīng)常使用的page移向到舊子列表中,最終導(dǎo)致被剔除瞪醋。
因此InnoDB做了Making the Buffer Pool Scan Resistant
這個優(yōu)化。簡單的說就是讀取Page插入到BP的時候不是插入到midpoint而是先插入到old sublist的tail 银受,第一次被讀取的時候,再移到midpoint宾巍。
另外的一些參數(shù)優(yōu)化可參考官方文檔:
Making the Buffer Pool Scan Resistant
Configuring InnoDB Buffer Pool Prefetching (Read-Ahead)
1.2 Change Buffer
??Change Buffer(以下簡稱CB) 存在于內(nèi)存,當(dāng)對輔助索引(secondary index) 進(jìn)行DML操作時顶霞,BP沒有其相應(yīng)的Page,會將這些變更緩存到CP中选浑。當(dāng)CB里的Page被read的時候,會被合并到BP中古徒。當(dāng)臟頁超過一定比例時,會將其flush磁盤中隧膘。 CB的內(nèi)存默認(rèn)占BP的25%寺惫。
??個人認(rèn)為刷新頁到磁盤時沒有將CB的數(shù)據(jù)刷到磁盤,因?yàn)镃B中的數(shù)據(jù)只有在被讀到的時候才會和BP合并肌蜻,因此數(shù)據(jù)庫對應(yīng)的舊數(shù)據(jù)也不會被讀,所以也不急著和flush到磁盤蒋搜。判莉。豆挽。券盅。
1.2.1 CB帶來的提升
??原本修改BP不存在的Page需要先從磁盤讀取(一次IO操作)到內(nèi)存锰镀,然后寫redo log。
??引入CB后泳炉,會先緩存在CB,然后寫redo log花鹅。
由于CB的存在,避免了從磁盤讀取輔助索引到緩沖池所需的大量隨機(jī)訪問I / O刨肃。
輔助索引不支持Change Buffer的情況:
- 如輔助索引包含降序索引列
- 主鍵包含降序索引
PS. 降序索引在8.0以上版本才支持。
1.3. Adaptive Hash Index
??Adaptive Hash Index對InnoDB在BP的查詢有很大的優(yōu)化真友。針對BP中熱點(diǎn)頁數(shù)據(jù),構(gòu)建索引(一般使用索引鍵的前綴構(gòu)建哈希索引)锻狗。因?yàn)镠ASH索引的等值查詢效率遠(yuǎn)高于B+ tree,所以當(dāng)查詢命中hash轻纪,就能很快返回結(jié)果,不用再去遍歷B+ tree刻帚。
1.4. Log Buffer
??Log Buffer是保存要寫入磁盤上日志文件的數(shù)據(jù)的內(nèi)存區(qū)域。默認(rèn)大小16MB崇众。相關(guān)參數(shù)設(shè)置如下
- innodb_log_buffer_size : 設(shè)置大小
- innodb_flush_log_at_trx_commit : 刷新行為航厚。默認(rèn)值:1锰蓬, 取值有0幔睬,1芹扭,2三種麻顶。
- 0: 日志每秒刷新到磁盤舱卡。 未刷新日志的事務(wù)會在mysql崩潰中丟失
- 1: 每次提交事務(wù)時,寫入并刷新日志到磁盤
- 2: 每次提交事務(wù)后寫入日志轮锥,并每秒刷新一次磁盤。 未刷新日志的事務(wù)可能會在mysql崩潰中丟失舍杜。
- innodb_flush_log_at_timeout:每幾秒刷新日志,取值范圍 [1,2700] (second)
二 InnoDB 磁盤結(jié)構(gòu)
2.1 Tablespaces
2.1.1 The System Tablespace
The System Tablespace 是Doublewrite Buffer和Change buffer的儲存區(qū)域既绩,也有用戶創(chuàng)建的表和索引數(shù)據(jù)。該空間的數(shù)據(jù)文件通過參數(shù)innodb_data_file_path
控制熬词,默認(rèn)值是ibdata1:12M:autoextend
(文件名為ibdata1吸重,大小略大于12MB,自動擴(kuò)展)嚎幸。
8.0之后InnoDB將元數(shù)據(jù)(以前的.frm文件,存表結(jié)構(gòu))存在該區(qū)域的數(shù)據(jù)字典中(data dictionary)嫉晶。
2.1.2 File-Per-Table Tablespaces
File-Per-Table Tablespaces 默認(rèn)開啟,為每個表都獨(dú)立建一個.ibd文件。 通過參數(shù)innodb_file_per_tabl
可以設(shè)置關(guān)閉替废,這樣的話所有表數(shù)據(jù)是都存在The System Tablespace的ibdata。
2.1.3 General Tablespaces
General Tablespaces 是通過CREATE TABLESPACE
創(chuàng)建的共享表空間椎镣。
2.1.4 Undo Tablespaces
Undo Tablespaces保存的是undo log ,用于回滾事務(wù)状答。
該表空間有rollback segments,rollback segments是用于存 undo log segments, 而undo log segments存的就是undo logs刀崖。
mysql啟動的時候,默認(rèn)初始兩個undo tablespace亮钦。因?yàn)閟ql執(zhí)行前必須要有rollback segments。而兩個undo tablespace才支持automated truncation of undo蜂莉。
2.1.5 Temporary Tablespaces
InnoDB把 Temporary Tablespaces分為兩種,session temporary tablespaces 和global temporary tablespace巡语。
session temporary tablespaces存儲的是用戶創(chuàng)建的臨時表和內(nèi)部的臨時表,一個session最多有兩個表空間(用戶臨時表和內(nèi)部臨時表)男公。
global temporary tablespace儲存用戶臨時表的回滾段(rollback segments )。
2.2 Doublewrite Buffer
Doublewrite Buffer位于The System Tablespace合陵。在BP的頁數(shù)據(jù)刷到磁盤真正的位置前,會先將數(shù)據(jù)存在doublewrite buffer拥知。 這步操作是直接將數(shù)據(jù)作為順序塊,調(diào)用OS的fsync()方法寫入到doublewrite buffer低剔。
雖然數(shù)據(jù)寫了兩次,但是性能還是比兩次IO低的襟齿。
此外fsync保證了BP中的數(shù)據(jù)寫到磁盤中,即使數(shù)據(jù)庫掛了猜欺,還可以從doublewrite buffer中還原數(shù)據(jù)。
還可以解決頁斷裂的問題
2.3 Redo log
redo log記錄的DML操作的日志开皿,可以用來宕機(jī)后的數(shù)據(jù)前滾。(在log buffer的redo log日志會在宕機(jī)中丟失)
2.4 undo log
undo log記錄數(shù)據(jù)更改前的快照(感覺就是備份)赋荆,在數(shù)據(jù)需要回滾就可以根據(jù)undo log恢復(fù)。
那些undo log 記錄關(guān)于在global temporary tablespace 的用戶臨時表的回滾信息窄潭,不會在回滾中恢復(fù)。
總結(jié)
個人記錄,并不一定都是對的信认,還是得好好看看官方文檔,不斷琢磨。嫁赏。。
https://dev.mysql.com/doc/refman/8.0/en/innodb-in-memory-structures.html
https://dev.mysql.com/doc/refman/8.0/en/innodb-on-disk-structures.html