MySQL架構(gòu):
-
Connectors:MySQL向外提供的交互接口:
Java等語言可以通過該接口實現(xiàn)和SQL的交互萧吠,操作SQL語句。
-
Management Service & Utilities:管理服務(wù)組件和工具組件:
提供對MySQL的集成管理中鼠,包括:備份色难,恢復,安全管理等躁绸。
-
Connection Pool:連接池組件:
負責監(jiān)聽客戶端到MySQL的請求裕循,創(chuàng)建線程負責之間的通信。
-
SQL Interface:SQL接口組件:
接收客戶端的SQL命令净刮,將結(jié)果返回客戶端剥哑。
-
Parser:查詢分析器組件:
分析SQL的合法性,并解析SQL的數(shù)據(jù)結(jié)構(gòu)淹父。
-
Optimizer:優(yōu)化器組件:
對SQL進行優(yōu)化分析株婴。
-
Caches & Buffers:緩存組件:
SQL結(jié)果等緩存。
-
Pluggable Storage Engine:插拔式存儲引擎:
可插拔式的存儲引擎暑认,用于表的創(chuàng)建困介,數(shù)據(jù)檢索,索引創(chuàng)建等蘸际;也可滿足自定義的存儲引擎開發(fā)座哩。
-
File System:物理文件:
實際存儲數(shù)據(jù)的文件。
-
Files & Logs:文件和日志:
存儲各式各樣的日志文件粮彤。
其中MySQL的關(guān)鍵特點就是可插拔的存儲引擎根穷;其中InnoDB是MySQL的默認存儲引擎,也是應(yīng)用最為廣泛的存儲存儲引擎导坟,本文主要介紹InnoDB存儲引擎的關(guān)鍵特性以及這些特性的一些思考屿良。
數(shù)據(jù)庫和數(shù)據(jù)實例的區(qū)別:
- 數(shù)據(jù)庫是文件的集合,是依照某種數(shù)據(jù)模型組織起來并存放于二級存儲器中的數(shù)據(jù)集合惫周;
- 數(shù)據(jù)庫實例是程序管引,是位于用戶與操作系統(tǒng)之間的一層數(shù)據(jù)管理軟件;
InnoDB關(guān)鍵特性
InnoDB有以下關(guān)鍵特性闯两,其中前三個是數(shù)據(jù)庫最通用的特性:
Change Buffer(寫緩存)
Double Write(二次寫)
Adaptive Hash Index(自適應(yīng)哈希索引)
Async IO(異步IO)
Flush Neighbor Page(屬性鄰接頁)
1. Change Buffer
Change Buffer是InnoDB中最特殊的一個特性。Change Buffer是從InnoDB 1.0.x版本之后的引入的概念谅将,在1.0.x版本之前叫Insert Buffer(插入緩存)漾狼。Insert Buffer顧名思義是針對Insert的緩存。
1.1 問題誕生背景
對于InnoDB饥臂,所有的數(shù)據(jù)逊躁,索引等都是以文件的形式存儲,以B+樹的形式存儲隅熙。 InnoDB的索引分為兩種:聚簇索引(Primary Index)和非聚簇索引(Secondary Index)稽煤;其中聚簇索引的B+樹葉子節(jié)點存放的是真實的數(shù)據(jù)核芽;而非聚簇索引的葉子節(jié)點存放的是聚簇索引的主鍵值。
我們先從索引的角度來描述下問題的背景:
對于聚簇索引酵熙,主鍵是唯一的轧简;當插入新的數(shù)據(jù)時,需要檢查下磁盤是否有主鍵沖突匾二,這步磁盤訪問必不可少哮独;此外,一般對于主鍵的插入是順序的(比如id自增列)察藐,這樣磁盤是順序讀寫的皮璧,有較好的性能。
對于非聚簇索引分飞,列值不唯一悴务;當插入新的數(shù)據(jù)時,插入的數(shù)據(jù)很難是按遞增的順序插入的譬猫,這時候?qū)τ诓迦氩僮鞫际请S機的讯檐;如果有大量的插入操作,則會有大量的隨機IO删窒,會嚴重影響磁盤的性能裂垦。
因此Insert Buffer誕生的問題背景是: 大量的非聚簇索引插入操作?肌索?蕉拢?
產(chǎn)生的問題背景也反映了Insert Buffer需要滿足兩點:
必須是非聚簇索引;
索引的數(shù)據(jù)不是唯一的诚亚;(后面也會有介紹)
1.2 內(nèi)部實現(xiàn)
- MySQL數(shù)據(jù)存儲包含內(nèi)存和磁盤兩部分晕换;
- 內(nèi)存緩沖池以頁(Page)為單位,緩存最熱的是:數(shù)據(jù)頁和索引頁站宗;
- InnoDB以變種LRU(加了mid位置和時間的概念闸准,非常類似于JVM的內(nèi)存管理)的算法來管理緩沖池,解決了“預(yù)讀失效”和“緩沖池污染”的問題梢灭;
(1)情況一 當要插入的數(shù)據(jù)已經(jīng)在緩沖池了夷家,則只需要插入redo日志文件一次磁盤操作;但redo的磁盤是順序?qū)懨羰停屎芨呖饪欤灰虼诉@種情況不需要Insert Buffer。
緩沖池會定期的刷新到磁盤上钥顽,而不是每次都刷新义屏,這樣會降低磁盤的IO,提升性能,說白了就是批量寫(可能會有同一個數(shù)據(jù)頁的合并操作)闽铐。
(2)情況二 當要插入的數(shù)據(jù)不再緩沖池中蝶怔,這時候需要怎么辦? 為了避免大量的隨機IO兄墅,提出了Insert Buffer的概念踢星;當插入數(shù)據(jù)時,先把數(shù)據(jù)插入到Insert Buffer中察迟;當需要回刷磁盤時斩狱,會把Insert Buffer中的數(shù)據(jù)進行merge后寫入磁盤(因為有merge,為了表示現(xiàn)有頁的空閑空間扎瓶,還需要一個特殊的頁來保存每個非聚簇索引頁的空閑空間)所踊,降低了磁盤隨機IO。Insert Buffer也是B+樹的結(jié)構(gòu)概荷,插入數(shù)據(jù)時也是按照頁來組織聚簇索引和非聚簇索引數(shù)據(jù)秕岛。
舉個形象的例子來說明Insert Buffer的具體作用: 圖書管理員進行書籍整理,有兩種做法:
每歸還一本書误证,就去對應(yīng)的書架上歸還這本書继薛;
先把書放在柜臺,等書達到一定量的時候愈捅,進行批量的放回對應(yīng)的書架遏考;
正常人都會選擇第二種做法;而柜臺就是Insert Buffer蓝谨,歸還的書會先在柜臺上進行整理灌具,合并,然后一起放回書架譬巫,減少了書架的隨機訪問咖楣。
在MySQL5.5之后,不僅針對insert操作芦昔,還針對update和delete操作诱贿,改名為Change Buffer,原理是一致的。
Change Buffer還有一個細節(jié)點咕缎,當Change Buffer中的有數(shù)據(jù)沒有寫到磁盤前珠十,數(shù)據(jù)庫宕機了,這個時候Change Buffer的數(shù)據(jù)就恢復不了了凭豪,因此鑒于這種情況宵睦,InnoDB會把Change Buffer中的數(shù)據(jù)定期通過merge操作刷回表空間中的索引文件。
Change Buffer結(jié)構(gòu)圖:從圖中可以看出墅诡,Change Buffer并不僅僅指的是內(nèi)存中的一塊,還包含了物理磁盤上的共享表空間。
1.3 缺點
如果有大量的DML變更操作末早,數(shù)據(jù)宕機后烟馅,會導致恢復的時間較長;
有大量插入的時候然磷,會導致占用較多的Buffer Pool內(nèi)存郑趁,會影響其他數(shù)據(jù)的空間;
對于不同的硬件配置和負載姿搜,Change Buffer無法進行控制寡润,比如磁盤和SSD;
2. Double Write
從IO的角度來看舅柜,InnoDB是以頁為維度來讀取數(shù)據(jù)梭纹,正常InnoDB的頁可以配置為4K,8K致份,16K;而文件系統(tǒng)的IO讀寫最小單位是4K变抽,也有些是1K;磁盤的讀寫最小單位是扇區(qū)(512KB)氮块。
由于各系統(tǒng)以及硬件IO讀寫的單位不一致绍载,往往底層的單位要小于上層的單位,因此上層就會存在部分寫的場景:當寫一部分數(shù)據(jù)的時候滔蝉,機器宕機了击儡,這樣就會導致部分寫的場景。(磁盤是由硬件保證蝠引,要么512KB全部寫成功阳谍,要么都失敗,不存在部分寫的場景)
2.1 問題誕生背景
由上述知道立肘,InnoDB的IO最小單位是頁,正常大小為16K(可以配置為4K边坤,8K等);當緩沖池中的臟頁回寫磁盤時谅年,磁盤的頁和緩沖池的頁是對等的茧痒,也就是要回寫16K的數(shù)據(jù)到磁盤;而文件系統(tǒng)的讀寫單位可能是4K融蹂;這樣就需要寫入4次旺订,才能完整的把臟頁刷回去;如果在寫2次的時候超燃,機器斷電宕機了区拳,這個時候磁盤的頁就被污染了。
基于這種場景意乓,InnoDB誕生了Double Write的特性樱调,用于解決partial page write(部分寫)的問題。
2.2 內(nèi)部實現(xiàn)
參考Change Buffer的設(shè)計,Double Write也在Buffer Pool中開辟一塊內(nèi)存笆凌,用來存放修改的臟頁圣猎;并在磁盤的共享表中間中存放臟頁,Double Write的邏輯如下圖所示:Double Write的步驟:
當觸發(fā)臟頁刷新時乞而,先把臟頁拷貝到Double Write內(nèi)存中送悔;
接著把Double Write中的臟頁順序的寫到共享表空間中,這部分是順序?qū)懭氪疟P爪模,性能很高欠啤;
異步的將共享表空間的數(shù)據(jù)離散的寫入到各個表空間中;
Double Write如何宕機恢復的屋灌??声滥?
如果寫入Double Write Buffer時失敗眉撵,這個時候頁還沒有刷新回磁盤,也就沒有發(fā)生部分寫的問題落塑,因此直接從磁盤加載原始數(shù)據(jù)纽疟,并通過事務(wù)日志重新計算寫入Double Write Buffer。
如果寫入磁盤時憾赁,宕機污朽,由于共享表空間中副本數(shù)據(jù)恢復,重新寫入磁盤即可龙考。
為啥不用redo log解決部分寫的問題蟆肆??晦款? 這個涉及到redo log的數(shù)據(jù)設(shè)計炎功;如果redo log中保存了所有的數(shù)據(jù)和操作,那么redo log的size會非常大缓溅,不利于日志文件存儲蛇损;因此InnoDB對于redo log的設(shè)計是保存頁的指針之類的數(shù)據(jù);因此redo log無法恢復物理頁坛怪,因為redo log中不保存真實的數(shù)據(jù)淤齐。
2.3 缺點
雖然共享表空間的寫入是磁盤順序?qū)懀廊粫绊慚ySQL的性能袜匿;尤其是InnoDB為了保證寫入共享表空間數(shù)據(jù)的完整性更啄,在每次寫入后都會調(diào)用fsync操作等待磁盤操作結(jié)束,硬盤的fsync性能比較慢居灯;
3. Adaptive Hash Index
自適應(yīng)哈希索引是InnoDB內(nèi)部的一個優(yōu)化特性祭务,一般不需要開發(fā)人員關(guān)注内狗。
3.1 問題誕生背景
首先了解下InnoDB的數(shù)據(jù)存儲,InnoDB的數(shù)據(jù)和主鍵索引一起存儲义锥,主鍵索引的葉子節(jié)點存放的是數(shù)據(jù)其屏;非主鍵索引葉子節(jié)點存放的是主鍵的key值。
當通過非聚簇索引來查詢數(shù)據(jù)時缨该,根據(jù)B+索引樹查詢?nèi)~子節(jié)點的主鍵key,然后根據(jù)主鍵key再去主鍵索引的B+樹上找到對應(yīng)的葉子節(jié)點的數(shù)據(jù)。
可以看出來通過非聚簇索引來查詢數(shù)據(jù)時川背,需要訪問兩個B+樹贰拿,而自適應(yīng)哈希索引就是為了解決這個問題,直接構(gòu)造非聚簇索引key到真實數(shù)據(jù)的哈希索引熄云,哈希的時間復雜度是O(1)膨更;因此減少了兩次B+樹的查詢操作。
自適應(yīng)哈希索引是索引的索引 =稍省<允亍!
3.2 內(nèi)部實現(xiàn)
自適應(yīng)哈希索引的難點在于信息統(tǒng)計练般,要統(tǒng)計出查詢的熱點數(shù)據(jù)矗漾,為這些熱點數(shù)據(jù)建立哈希索引。比如對于同一條件的頻繁訪問薄料,可以構(gòu)造出哈希索引敞贡,下次同樣的條件可以直接獲取結(jié)果。
自適應(yīng)哈希索引的結(jié)構(gòu)如下圖所示:自適應(yīng)哈希索引實現(xiàn)的條件:
精確條件查詢摄职,以該條件查詢超過100次誊役;
頁訪問的次數(shù)N=頁記錄數(shù)/16; (內(nèi)部具體的信息統(tǒng)計涉及很多參數(shù)谷市,后續(xù)分析)
3.3 缺點
自適應(yīng)哈希索引也是占用Buffer Pool的空間蛔垢,會影響其他類型數(shù)據(jù)的空間容量;
自適應(yīng)哈希索引只支持精確條件查詢迫悠,不支持范圍查找鹏漆;
自適應(yīng)哈希索引只有在極端的情況下(大量固定條件的查詢),才有意義及皂,降低邏輯讀時間甫男;
4. Async IO
為了提供磁盤操作性能,現(xiàn)在的數(shù)據(jù)庫系統(tǒng)都是采用異步IO的方式來處理磁盤操作验烧。異步IO還支持批量操作板驳,把多個頁進行整合一起進行IO操作,如果是同一頁的數(shù)據(jù)碍拆,或者連續(xù)的數(shù)據(jù)若治,會提高磁盤的IO性能慨蓝。
5. Flush Neighbor Page
刷新鄰接頁是根據(jù)“局部性”原理,其工作原理是: 當刷新一個臟頁時端幼,InnoDB存儲引擎會檢測該頁所在區(qū)(extent)的所有頁礼烈,如果是臟頁,那么一起進行刷新婆跑。這樣做的好處顯而易見此熬,通過AIO可以將多個IO寫入操作合并為一個IO操作,故該工作機制在傳統(tǒng)機械磁盤下有著顯著的優(yōu)勢滑进。
InnoDB文件的格式是idb后綴犀忱,其中存放了表的數(shù)據(jù),又稱為表空間Tablespace扶关,表空間又分為多個段Segment阴汇;一個Segment又分為多個區(qū)Extent;一個區(qū)又分為多個頁Page节槐;一個頁包含了多個行Row搀庶。
后記
InnoDB的關(guān)鍵特性和文件的存儲結(jié)果密切相關(guān),后面會分析下InnoDB表數(shù)據(jù)的文件存儲結(jié)構(gòu)铜异。