數據庫的存儲引擎優化是一個揚長避短的過程
?這兩天要和一個數據庫廠商交流關于存儲引擎的事情,這些天這方面考慮的多一些,今天就來聊聊數據庫存儲引擎的事情。一說到存儲引擎,可能很多朋友就會說,某某存儲引擎技術比較先進,比傳統數據庫的好。實際上再先進的存儲引擎也有其缺點,可能先進只是指出現的較晚而已,并不是后出現的存儲引擎一定全面優于老的存儲引擎。數據庫的存儲引擎經過數十年的發展,實際上到現在為止也并沒有出現特別多的流派。大體上歸納起來還是B樹(含HEAP)和基于日志結構的存儲引擎這兩大類(最著名的是LSM-TREE)。雖然LSM-TREE的出現比B樹存儲引擎晚了二十多年,不過其出現并不是作為替代B樹引擎的,而是有著特定的目的的。
LSM-TREE的出現是在內存成本第一次大幅下降之后的,因此基于memtab可以大幅優化高并發寫入的性能,同時SSTABLE可以更加充分的利用存儲,更加有利于數據壓縮。LSM-TREE被大規模應用到關系型數據庫上則是SSD逐漸普及后才出現的,因為開銷巨大甚至可能導致系統不穩定的后臺壓縮讓對于延時十分敏感的OLTP系統無法承受。而SSD可以緩解這種問題。
B樹存儲引擎一般采用IN-PLACE-REPLACE,所以其性能相對穩定,雖然會因為PAGE的碎片而導致一些浪費,但是總體來說是較為均衡的。與LSM-TREE相比,因為B樹存儲引擎的這個特點導致并發寫入的性能是會遇到瓶頸的。幾年前我們測試過一個每隔5分鐘有數億條數據并發寫入,并需要進行實時統計分析的場景,在Oracle數據庫上在每秒寫入1000萬條以后明顯就很難提升了,而在LSM-TREE引擎的分布式系統中,很輕松就超過2000萬/秒。雖然在寫入上B樹存儲引擎的性能無法與LSM-TREE相媲美,不過B樹存儲引擎在數據讀取上有著明顯的優勢。在MVCC的實現上,以及對數據的復雜查詢上面,B樹存儲引擎都比LSM-TREE有明顯的優勢。雖然LSM-TREE存儲引擎在查找數據上也通過布魯姆過濾器以及內存主范圍索引等方式進行優化,但是其開銷還是會比B樹存儲引擎要大的多。目前很多基于LSM-TREE的分布式數據庫往往都是依靠并行掃描的方法,以眾敵寡,勉強和B樹結構的集中式數據庫打個平手。
實際上兩種存儲引擎的一些優缺點也并不容易區分清楚,如果站在某個立場上,就會有不同的分析結論。比如寫放大的問題上,LSM-TREE的支持者會說LSM-TREE結構更加緊湊,數據沒有碎片,而B樹存儲引擎經常會出現某個PAGE中只寫了很少一部分數據,導致寫被放大了。實際上LSM-TREE雖然不存在這種寫放大,但是一個KEY會被多處存儲,也會造成另外一個意義上的寫放大。再加上現代硬件對于寫IO的能力已經極大提高了,這個問題其實并不會對絕大多數場景造成影響。
從上面的分析來看,確實沒有完美的存儲引擎,每個引擎都有其優點,也同時必然有其缺點。我們要做的實際上是利用現代硬件的特點,盡可能地彌補其缺點,發揚其優點。隨著IO越來越好,CPU越來越便宜,LSM-TREE存儲引擎被越來越廣泛地使用也是一個很好的例子。
前些年我和INTEL合作研究傲騰內存的使用場景的時候,曾經考慮過是不是把沒有壓縮的sstable先存儲到傲騰內存里,在傲騰內存里做壓縮后,逐漸把歷史數據下沉到性能相對較差的持久存儲上。這樣可以大大降低壓縮帶來的負面影響。再用CGROUP隔離后臺壓縮進程,這樣就可以避免壓縮給數據庫帶來的抖動。
前些天我看到一篇北京大學Baoyue Yan的論文,他們提出了一種利用傲騰內存優化LSM-TREE存儲引擎的算法,在實踐中獲得了很好的效果,在TPCC基準測試中獲得了2倍的提升。
左邊的圖是基于傳統的LSM-TREE存儲引擎的數據庫,而右邊是他們優化過的方案。實際上這張圖并不完整,還缺少了一個傳統內存的區域。在傳統內存區域里,他們放置了可丟失的半持久化索引數據,傳統寫入memtab的數據被寫入非易失性內存中的sp-m,sp-m寫滿后被鎖定為sp-im,然后在非易失性內存中進行壓縮,寫入SSD的持久化存儲系統中。
因為主數據被寫入非易失性內存,因此通過WAL來保證數據庫的一致性需求也沒那么強烈了,因此可以使用更為輕量級的Recorder Ring來替換WAL,保證事務一致性。這種利用非易失性內存這種現代的硬件來優化數據庫架構,甚至顛覆傳統數據庫架構的嘗試是十分值得肯定的,也是十分有價值的。
可能有朋友要說了,非易失性內存那么貴,不是任何用戶用得起的,所以這種數據庫是不是很難普及啊。實際上說這句話的時候想想十年前,當時大家都在說SSD那么貴,不是任何人都用得起的。而現在,好像不是那么回事了吧。