數據庫內部存儲結構探索

 本文是左耳耗子推薦的Medium上的一篇關於MySQL的文章Some study on database storage internals,本人以爲文章十分好,就取得了做者的許可,自行進行了翻譯,原文連接見文末。本文是一篇介紹性的文字,因此文中並無對一些概念進行詳細介紹,好比說Sorted Strings Table結構和Bloom filters算法等專業概念,感興趣的小夥伴能夠學習參考中給出的連接或持續關注本人後續文章。算法

 我一直以來都在不斷的研究和探索數據庫的內部存儲原理。我認爲這個話題是很是巨大且複雜的,我努力所學也只佔其千萬分之一。在這篇文章中,我將會講解一些數據庫存儲的內部機制,數據庫是如何進行優化操做來提供驚人速度及其優點和缺點。數據庫

 當咱們談起數據庫內部存儲結構時,人們都會想到B樹或者B+樹,可是咱們在這裏並不會談論這些數據結構的原理,咱們會展現這些數據結構爲何適合做爲數據庫存儲的內部結構以及使用這些數據結構的目的。apache

 傳統的關係型數據將數據以B樹的形式存儲在磁盤上,它們也會在RAM上使用B樹維護這些數據的索引,來保證更快的訪問速度。插入的行存儲在B樹的葉子節點上,全部的中間節點用來存儲用於導航查詢語句的原數據。所以,當有數以百萬計的數據被插入到數據庫中時,索引和數據存儲會變得十分大。所以,爲了快速的訪問,須要從磁盤中加載全部數據到內存,可是RAM通常沒有這麼大的空間來存儲全部的數據。所以,數據庫必須從磁盤中讀取部分數據。這種加載數據的場景以下圖所示:緩存

B樹示意圖

 磁盤I/O花費的時間很長,是影響數據庫性能的主要緣由之一。B樹是支持隨機讀寫,in-place 替換,十分緊湊而且自平衡的數據結構,可是受磁盤I/O速度的限制。隨機讀意味着當訪問磁盤數據時,磁頭必須移動到柱面上的指定位置,所以會消耗大量時間。微信

 B樹被設計爲使用block的形式存儲數據,由於操做系統讀取讀取一個block的數據要比讀取單獨字節數據要快的多。MySQL的InnoDB存儲引擎的block大小爲16KB。這意味着每次你讀取或者寫入數據時,大小爲16KB的block數據會被從磁盤加載到RAM中,它會被寫入新的數據,而且再次寫回到磁盤上。假設數據庫表的每一行數據爲128字節(實際大小會變化),一個block(葉子節點)爲16KB,存儲了(16 * 1024) / 128 = 128行數據。B樹的高度通常小於10,可是每一層的節點數量卻不少,由此能夠管理數以萬計的數據。基於上述特性,B樹適合做爲數據內部存儲結構。數據結構

 所以,在B樹上進行讀操做是相對來講比較快速的,由於該操做只須要遍歷一些節點而且進行較少次數的磁盤I/O請求。並且,範圍查詢由於能夠將數據以block的形式進行獲取和操做而速度更快。你能夠進行下列操做來讓基於B-Tree的數據庫性能更好:併發

  • 減小索引節點數量:這是提高關係型數據庫性能的經常使用策略。索引越多,插入和更新操做須要管理的索引數量也越多。當數據庫數據運行時間愈來愈久時,就須要刪除一些老舊或者無用的索引,而且謹慎地添加新的索引。可是你也要注意,索引越少意味着查詢性能越差,你須要在查詢性能和插入更新性能之間進行取捨(譯者注:能夠考慮數據庫的讀寫比率)。
  • 順序插入:若是你能以主鍵大小爲基礎進行大量數據的順序插入,那麼插入數據的速度會十分的快。由於在插入過程當中,插入行所屬的block已經在內存中,因此數據庫能夠直接將行插入到內存的數據結構中,而後經過一次磁盤I/O提交到數磁盤中。固然,這些都取決於數據庫的具體實現,可是我認爲現代的數據庫通常都會進行相似的優化。

 可是B樹並非適合全部情景的最優存儲結構。對B樹結構的寫操做性能不好,比隨機讀還要差,由於數據庫必須從磁盤中加載數據對應的頁,而後修改它並沖洗新寫入到磁盤中。隨機寫入時平均有100字節每秒寫入速度,這個限制是因爲磁盤的基本工做原理。事實上,簡單依賴於緩存的使用,索引搜索和更多的內存能夠處理更多的讀操做,可是應付更多的寫操做就比較麻煩。當你須要寫入或更新大量的數據時,B樹結構並非最正確的選擇。長久以來,傳統數據庫進行了大量的優化,好比說InnoDB嘗試使用緩衝來減小磁盤I/O操做。具體操做以下所示:app

操做緩存示意圖

 數據庫寫操做能夠經過提高磁盤的帶寬來提高速度,可是目前關係型數據庫都沒有這樣作。並且關係型數據庫管理系統通常都是十分複雜的,由於他們使用鎖,併發,ACID事務等操做,這使得寫入操做更加複雜。分佈式

 當今信息時代,在好比消息、聊天、實時通信和物聯網等客戶爲中心的服務和大量無結構化數據的分佈式系統中,每小時都會進行數百萬計的寫入操做。所以,這些系統是以寫爲主的系統,爲了迎合這些系統的須要,數據庫須要可以擁有快速插入數據的能力。典型的數據庫並不能很好的知足相似的場景,由於它們沒法應付高可用性,儘量的最終一致性,無格式數據的靈活性和低延遲等要求。性能

 LSM樹(Log Structured Merge Tree)應運而生。LSM並非一種相似於B樹的數據結構,而是一個系統。在LSM系統中,並無對數據的in-place替換;一旦數據被寫入磁盤,它就不再會被修改。顯然,它是一種只能在末尾添加(append only)的寫入系統。一些日誌結構的文件系統好比ext3/4也使用相似的原理。所以,該系統就如同順序的記錄數據日誌通常。基本上,LSM系統利用了順序寫的優點。傳統的磁盤驅動的寫操做最高能夠達到100MB/s,現代的固態硬盤在順序寫時的速度則更快。事實上,固態硬盤驅動有一些內置的並行機制來讓它能夠同時寫入16到32MB的數據。LSM樹和固態硬盤的特性十分匹配。順序寫要比隨機寫快不少。

 爲了正確地理解上述場景,讓咱們簡單的看一下Facebook的Cassandra數據庫是如何使用LSM原則的。

LSM系統示意圖

 Cassandra或者任何LSM系統都會維護一個或者多個用來在寫入磁盤前存儲數據的內存數據結構(如上圖中的memtable),好比說子平衡樹(AVL)、紅黑樹、B樹或者跳錶。該內存數據結構維護一個排序的數據集。不一樣的LSM實現互使用不一樣的數據結構來適應不一樣的需求,並不存在標準的LSM實現。當內存中存儲的數據超過配置的閾值時,內存中存儲的數據就會被放置在將會被寫入磁盤的隊列中。爲了flush數據,Cassandra順序地寫入排序的數據到磁盤中。磁盤維護一個叫作「SSTable」(Sorted Strings Table)的數據結構,該數據就是寫入文件數據的有序的快照,SSTable是不可變的。LSM系統能夠管理磁盤上的多個文件。

 所以,若是數據在內存中沒有被發現,Cassandra須要掃描全部磁盤上的SSTables來搜索該數據。所以,Cassandra的讀操做相對來講要比寫操做慢,可是這裏有一些能夠處理的方法。Cassandra或者其餘LSM系統會在後臺運行壓縮程序來減小SSTable的數量。壓縮程序對SSTable進行歸併排序,在新的SSTable找那個插入新的排序數據而且刪除老的SSTables。可是使用壓縮程序有時候沒法應付數據庫中數以百萬計的更新操做。

 所以,一些機率數據結構(probabilistic data structures)好比Bloom filters被應用來快速判斷是否一些數據存在於SSTable。Bloom filters十分適合對內存中的數據進行判斷,由於它須要進行大量的隨機查詢來進行數據是否存在的機率性判斷。Bloom filters算法能夠極大地減小遍歷查詢SSTables的花費。所以,LSM系統解決了在大數據中寫操做須要花費大量時間的問題。LSM系統也有Read amplification的問題-會讀取出比它實際須要更多的數據。所以,還有介於B Tree和LSM Tree之間的解決方法來給出咱們最優(不必定準確)的讀寫效率嗎?

 Fractal Tree Index是基於B-Tree的數據結構。依據開發人員給出的benchmark,該數據結構有比B-Tree更優良的性能。Fractal tree支持在非葉節點上的信息緩存。MySQL的高性能存儲引擎Tokudb就使用了Fractal tree。

Fractal Tree Index示意圖

 如上圖所示,在Fractal Tree中,你進行的添加列,刪除列,插入,更新等任何操做都會被當作操做消息存儲在非葉節點上。因爲操做只是被簡單地存儲在緩存或者任何次級索引緩存(secondary index buffer)中,因此,全部的操做都會被迅速執行結束。當某一個節點的緩存滿了以後,這些操做消息會依次從根節點,通過非葉節點,向葉節點進行傳遞。葉節點仍然存儲着真實數據。當進行讀時,讀操做會考慮查詢路徑節點上的全部操做消息來獲取真實的數據狀態。可是因爲tokudb會盡力將全部非葉節點緩存在內存中,因此這一過程也很快。

 tokubd中的block最大能夠達到4MB,而不是InnoDB中的16KB。這樣的大小能夠容許一次I/O操做時加載或寫回更多的數據,這也有助於一次壓縮更多數據來減小磁盤上數據的存儲大小。所以,tokudb強調藉助更大的block大小可以實現更好的數據壓縮和更少的磁盤I/O。tokudb宣稱它們的存儲引擎比InnoDB更快,提供比InnoDB更快的讀寫吞吐,而且tokudb也宣稱本身有更少的碎片(fragmentation)問題,它也支持多集羣索引等。下圖是benchmark的相關統計圖:

benchmark統計圖

 只有你係統中的benchmark能夠幫助你判斷正確的數據點和需求解決方案。可是MySQL的存儲引擎會持續地不斷改進和支持新出現的需求。LSM樹是爲了高寫入場景的系統,然而B樹是爲了傳統的場景應用。Fractal樹的索引改進了B樹索引存在的一些缺陷。所以,將來會不斷地出現技術上的革新,包括數據庫存儲技術,硬件,磁盤驅動和操做系統,讓咱們拭目以待。

訂閱最新文章,歡迎關注個人微信公衆號

參考

相關文章
相關標籤/搜索