MySQL探秘(三):InnoDB的内存结构和特性(可靠性和持久性)
?MySQL區(qū)別于其他數(shù)據(jù)庫的最為重要的特點就是其插件式的表存儲引擎。而在眾多存儲引擎中,InnoDB是最為常用的存儲引擎。從MySQL5.5.8版本開始,InnoDB存儲引擎是默認(rèn)的存儲引擎。
?InnoDB存儲引擎支持事務(wù),其設(shè)計目標(biāo)主要面向在線事務(wù)處理(OLTP)的應(yīng)用。其特點是行鎖設(shè)計、支持外鍵,并支持非鎖定讀,即默認(rèn)讀操作不會產(chǎn)生鎖。
?InnoDB通過使用多版本并發(fā)控制(MVCC)來獲取高并發(fā)性,并且實現(xiàn)了SQL標(biāo)準(zhǔn)的4中隔離級別,默認(rèn)為REPEATABLE級別。同時,使用一種被稱為next-key-locking的策略來避免幻讀現(xiàn)象的產(chǎn)生。除此之外,InnoDB存儲引擎還提供了插入緩沖(insert buffer)、二次寫(double write)、自適應(yīng)哈希索引(adaptive hash index)、預(yù)讀(read ahead)等高性能和高可用的功能。
?上圖詳細(xì)顯示了InnoDB存儲引擎的體系架構(gòu),從圖中可見,InnoDB存儲引擎由內(nèi)存池,后臺線程和磁盤文件三大部分組成。接下來我們就來簡單了解一下內(nèi)存相關(guān)的概念和原理。
緩沖池
?InnoDB存儲引擎是基于磁盤存儲的,并將其中的記錄按照頁的方式進(jìn)行管理。但是由于CPU速度和磁盤速度之間的鴻溝,基于磁盤的數(shù)據(jù)庫系統(tǒng)通常使用緩沖池記錄來提高數(shù)據(jù)庫的的整體性能。
?在數(shù)據(jù)庫中進(jìn)行讀取操作,首先將從磁盤中讀到的頁放在緩沖池中,下次再讀相同的頁中時,首先判斷該頁是否在緩沖池中。若在緩沖池中,稱該頁在緩沖池中被命中,直接讀取該頁。否則,讀取磁盤上的頁。
?對于數(shù)據(jù)庫中頁的修改操作,則首先修改在緩沖池中的頁,然后再以一定的頻率刷新到磁盤上。頁從緩沖池刷新回磁盤的操作并不是在每次頁發(fā)生更新時觸發(fā),而是通過一種稱為CheckPoint的機制刷新回磁盤。
?所以,緩沖池的大小直接影響著數(shù)據(jù)庫的整體性能,可以通過配置參數(shù)innodb_buffer_pool_size來設(shè)置。
?具體來看,緩沖池中緩存的數(shù)據(jù)頁類型有:索引頁、數(shù)據(jù)頁、undo頁、插入緩沖(insert buffer)、自適應(yīng)哈希索引(adaptive hash index)、InnoDB存儲的鎖信息(lock info)和數(shù)據(jù)字典信息(data dictionary)。
?在架構(gòu)圖上可以看到,InnoDB存儲引擎的內(nèi)存區(qū)域除了有緩沖池之外,還有重做日志緩沖和額外內(nèi)存池。InnoDB存儲引擎首先將重做日志信息先放到這個緩沖區(qū)中,然后按照一定頻率將其刷新到重做日志文件中。重做日志緩沖一般不需要設(shè)置的很大,該值可由配置參數(shù)innodb_log_buffer_size控制。
數(shù)據(jù)頁和索引頁
?Page是Innodb存儲的最基本結(jié)構(gòu),也是Innodb磁盤管理的最小單位,與數(shù)據(jù)庫相關(guān)的所有內(nèi)容都存儲在Page結(jié)構(gòu)里。Page分為幾種類型,數(shù)據(jù)頁和索引頁就是其中最為重要的兩種類型。
插入緩沖(Insert Buffer)
?我們都知道,在InnoDB引擎上進(jìn)行插入操作時,一般需要按照主鍵順序進(jìn)行插入,這樣才能獲得較高的插入性能。當(dāng)一張表中存在非聚簇的且不唯一的索引時,在插入時,數(shù)據(jù)頁的存放還是按照主鍵進(jìn)行順序存放,但是對于非聚簇索引葉節(jié)點的插入不再是順序的了,這時就需要離散的訪問非聚簇索引頁,由于隨機讀取的存在導(dǎo)致插入操作性能下降。
?InnoDB為此設(shè)計了Insert Buffer來進(jìn)行插入優(yōu)化。對于非聚簇索引的插入或者更新操作,不是每一次都直接插入到索引頁中,而是先判斷插入的非聚集索引是否在緩沖池中,若在,則直接插入;若不在,則先放入到一個Insert Buffer中??此茢?shù)據(jù)庫這個非聚集的索引已經(jīng)查到葉節(jié)點,而實際沒有,這時存放在另外一個位置。然后再以一定的頻率和情況進(jìn)行Insert Buffer和非聚簇索引頁子節(jié)點的合并操作。這時通常能夠將多個插入合并到一個操作中,這樣就大大提高了對于非聚簇索引的插入性能。
兩次寫(Double Write)
?如果說Insert Buffer給InnoDB存儲引擎帶來了性能上的提升,那么Double Write帶給InnoDB存儲引擎的是數(shù)據(jù)頁的可靠性。
?如上圖所示,Double Write由兩部分組成,一部分是內(nèi)存中的double write buffer,大小為2MB,另一部分是物理磁盤上共享表空間連續(xù)的128個頁,大小也為2MB。在對緩沖池的臟頁進(jìn)行刷新時,并不直接寫磁盤,而是 1. 通過memcpy函數(shù)將臟頁先復(fù)制到內(nèi)存中的該區(qū)域(doublewrite buffer),1.1?之后通過doublewrite buffer再分兩次,每次1MB順序地寫入共享表空間的物理磁盤上(doublewrite),然后馬上調(diào)用fsync函數(shù),同步磁盤,避免操作系統(tǒng)緩沖寫帶來的問題(map技術(shù)的過程)。2. 在完成doublewrite頁的寫入后,再講doublewirite buffer中的頁寫入各個表空間文件中。
?如果操作系統(tǒng)在將頁寫入磁盤的過程中發(fā)生了崩潰(發(fā)生在第2步),在恢復(fù)過程中,InnoDB存儲引擎可以從共享表空間中的doublewrite中找到該頁的一個副本,將其復(fù)制到表空間文件中,再應(yīng)用重做日志。
重做日志(Redo Log Buffer)
?當(dāng)緩沖池中的頁的版本比磁盤要新時,數(shù)據(jù)庫需要將新版本的頁從緩沖池刷新到磁盤。但是如果每次一個頁發(fā)送變化,就進(jìn)行刷新,那么性能開銷是非常大的,于是InnoDB采用了Write Ahead Log策略,即當(dāng)事務(wù)提交時,先寫重做日志,然后再擇時將臟頁寫入磁盤。如果發(fā)生宕機導(dǎo)致數(shù)據(jù)丟失,就通過重做日志進(jìn)行數(shù)據(jù)恢復(fù)。
?InnoDB存儲引擎會首先將重做日志信息先放入重做日志緩沖中,然后再按照一定頻率將其刷新到重做日志文件。重做日志緩沖一般不需要設(shè)置得很大,因為一般情況每一秒鐘都會將重做日志緩沖刷新到日志文件中??赏ㄟ^配置參數(shù)innodb_log_buffer_size控制,默認(rèn)為8MB。
?除了每秒刷新機制之外,每次事務(wù)提交時重做日志緩沖也會刷新到日志中。InnoDB是事務(wù)的存儲引擎,其通過Force Log at Commit機制實現(xiàn)事務(wù)的持久性,即當(dāng)事務(wù)提交時,必須先將該事務(wù)的所有日志寫入到重做日志文件進(jìn)行持久化,然后事務(wù)的提交操作完成才算完成。InnoDB的寫入機制大致如下圖所示。
?為了確保每次日志都寫入到重做日志文件,在每次將重做日志緩沖寫入重做日志后,必須調(diào)用一次fsync操作,將緩沖文件從文件系統(tǒng)緩存中真正寫入磁盤。
?可以通過innodb_flush_log_at_trx_commit來控制重做日志刷新到磁盤的策略。該參數(shù)默認(rèn)值為1,表示事務(wù)提交必須進(jìn)行一次fsync操作,還可以設(shè)置為0和2。0表示事務(wù)提交時不進(jìn)行寫入重做日志操作,該操作只在主線程中完成,2表示提交時寫入重做日志,但是只寫入文件系統(tǒng)緩存,不進(jìn)行fsync操作。由此可見,設(shè)置為0時,性能最高,但是喪失了事務(wù)的一致性。
自適應(yīng)哈希索引(Adaptive Hash Index)
?InnoDB會根據(jù)訪問的頻率和模式,為熱點頁建立哈希索引,來提高查詢效率。InnoDB存儲引擎會監(jiān)控對表上各個索引頁的查詢,如果觀察到建立哈希索引可以帶來速度上的提升,則建立哈希索引,所以叫做自適應(yīng)哈希索引。
?自適應(yīng)哈希索引是通過緩沖池的B+樹頁構(gòu)建而來,因此建立速度很快,而且不需要對整張數(shù)據(jù)表建立哈希索引。其有一個要求,即對這個頁的連續(xù)訪問模式必須是一樣的,也就是說其查詢的條件(WHERE)必須完全一樣,而且必須是連續(xù)的。
鎖信息(lock info)
?我們都知道,InnoDB存儲引擎會在行級別上對表數(shù)據(jù)進(jìn)行上鎖。不過InnoDB也會在數(shù)據(jù)庫內(nèi)部其他很多地方使用鎖,從而允許對多種不同資源提供并發(fā)訪問。數(shù)據(jù)庫系統(tǒng)使用鎖是為了支持對共享資源進(jìn)行并發(fā)訪問,提供數(shù)據(jù)的完整性和一致性。關(guān)于鎖的具體知識我們之后再進(jìn)行詳細(xì)學(xué)習(xí)。
數(shù)據(jù)字典信息(Data Dictionary)
?InnoDB有自己的表緩存,可以稱為表定義緩存或者數(shù)據(jù)字典。當(dāng)InnoDB打開一張表,就增加一個對應(yīng)的對象到數(shù)據(jù)字典。
?數(shù)據(jù)字典是對數(shù)據(jù)庫中的數(shù)據(jù)、庫對象、表對象等的元信息的集合。在MySQL中,數(shù)據(jù)字典信息內(nèi)容就包括表結(jié)構(gòu)、數(shù)據(jù)庫名或表名、字段的數(shù)據(jù)類型、視圖、索引、表字段信息、存儲過程、觸發(fā)器等內(nèi)容。MySQL INFORMATION_SCHEMA庫提供了對數(shù)據(jù)局元數(shù)據(jù)、統(tǒng)計信息、以及有關(guān)MySQL server的訪問信息(例如:數(shù)據(jù)庫名或表名,字段的數(shù)據(jù)類型和訪問權(quán)限等)。該庫中保存的信息也可以稱為MySQL的數(shù)據(jù)字典。
參考
-
1.《MySQL技術(shù)內(nèi)幕InnoDB存儲引擎》
-
2.《高性能MySQL》
-
3. 姜承曉老師的InnoDB架構(gòu)圖
總結(jié)
以上是生活随笔為你收集整理的MySQL探秘(三):InnoDB的内存结构和特性(可靠性和持久性)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MySQL探秘(二):SQL语句执行过程
- 下一篇: MySQL探秘(四):InnoDB的磁盘