軟硬體結合,分散式資料庫 ZNBase 儲存架構優化實踐
ZNBase 是開放原子開源基金會旗下的首個分散式資料庫專案,由浪潮大資料團隊開源並捐贈。本文將介紹 ZNBase 的儲存架構,以及 ZNBase 技術團隊在其 KV 儲存引擎基礎上所做的優化實踐。
ZNBase 整體儲存架構
云溪資料庫 ZNBase 採用分層架構,分為計算層與儲存層,其總體架構如下圖所示:
在 OLTP 場景下,當開發人員向叢集傳送 SQL 語句時,資料最終會以鍵值對 KV 的形式對儲存層進行讀寫。每個 ZNBase 節點啟動時,至少會包含一個儲存節點。儲存層預設採用 KV 儲存引擎 RocksDB 負責儲存資料。每個儲存例項都可能包含多個 Range,Range 是最底層的 KV 資料單元。Range 使用 Raft 一致性協議在叢集間進行復制。
為了支援 HTAP 場景,ZNBase 的行存資料會通過 Raft Learner 同步到列存引擎,儲存層還擴充套件了向量介面,通過列式儲存、計算下推、多節點平行計算滿足業務應用的 AP 需求。另外儲存層還擴充套件了時序介面,可以進行時序資料管理。
接下來將著重介紹 ZNBase 儲存層架構中的 KV 儲存叢集。
RocksDB 引擎
ZNBase 的儲存層預設採用 RocksDB 來儲存資料。RocksDB 是由 Facebook 開源的高效能 KV 儲存引擎,讀寫資料可以是任意位元組流,其官方架構如圖所示,是一種 LSM-Tree 的實現:
RocksDB 寫入流程如下:
1、以 batch 形式先順序寫入 WAL 檔案用於故障恢復
2、再寫入記憶體中的 Memtable,Memtable 預設以 SkipList 形式儲存
3、Memtable 寫滿一定大小,預設 64MB,會轉為不可變的 Immutable。
4、非同步執行緒會將 Immutable 刷到磁碟 L0 層,變為 SST 檔案。
5、磁碟中使用多層來管理 SST 檔案,通過合併過程將上層的 SST 檔案落到下層,在合併過程中會進行 GC 清理。
由此可見,RokcsDB 最新的資料是在記憶體或者上層的 SST 檔案裡,所以讀取時優先讀取 Memtable 和 Immutable,再依此讀取各層檔案。剛寫入的熱資料,可以更快被讀到。另外 RocksDB 還提供了 Block Cache 進行讀快取。
RocksDB 本身是一個 LSM-Tree 架構的高速 KV 儲存引擎,讀寫都會盡量使用記憶體。RocksDB 提供原子的批量寫入、快照等功能,方便上層實現事務控制。基於 RocksDB 也支援高度安全的 AES 演算法對儲存在磁碟上的資料加密,這樣即使磁碟被竊取,磁盤裡的資料也無法被訪問。
由於 RocksDB 採用 LSM-Tree 架構,同樣也存在一定的問題。比如在大資料量下有比較高的讀放大、寫放大、空間放大,效能衰減也比較厲害。為了提高 ZNBase 在海量資料下的效能表現,ZNBase 團隊結合浪潮的硬體優勢,開發了使用 SPDK 驅動在專用硬體 ZNS SSD 上進行軟硬體融合的儲存引擎;另外為了更有效的利用記憶體,獲得更快的讀寫速度,在大記憶體場景下也開發了準記憶體引擎的實現。
SPDK + ZNS SSD
固態硬碟(SSD)正在迅速擴充套件它在資料中心中的份額,相較於傳統儲存介質,新的快閃記憶體介質具有效能,耗電,機架空間等等方面的優勢。
而浪潮自研的 ZNS SSD,在容量、壽命、成本、易用性、效能等方面實現飛躍式提升。ZNS SSD 即分割槽名稱空間固態硬碟,可以將 FTL(Flash Translation Layer)暴露給使用者以充分發揮 SSD 效能。ZNS 技術針對雲場景應用,主適用於大容量空間儲存的資料,例如高清視訊、影象等。ZNBase 與 ZNS SSD 整合,通過智慧資料部署可以實現更好的空間運⽤,獲得降低一倍以上的寫放大;檔案可根據生命週期進行資料分割槽隔離,實現最低化垃圾回收;SST 檔案可根據 LSM 分層進行清晰化冷熱資料分離,提升訪問效率;最小化的寫放大可提升讀取效能,減少合併成本和垃圾回收開銷;理論上,ZNS SSD 可帶來 15% 的效能提升和 10% 的成本收益。
由於 SSD 本身的物理特性,其資料的訪問相較於傳統介質來說已經非常快了,而效能的瓶頸就是出在計算機與裝置連線的介面和協議上面。舉個直觀的例子,我們從北京乘飛機到美國,按照現在的飛行速度,在天上需要 13 個小時。這種情況下,安檢的時間,過海關的時間,候機的時間,加起來 3 個小時,相對於總共的 13+3=16 個小時也不算長。設想如果現在飛機的飛行速度提高了 100 倍,飛行時間從 13 小時縮短至 10 分鐘,這時 3 個小時的地面手續流程就顯得很沒有效率了。換言之,在儲存硬體效能高速發展的今天,儲存軟體協議棧的效能和效率在儲存整體系統中的地位越來越重要。
SPDK ( Storage performance development kit ) 由 Intel 發起,提供了一組用於編寫高效能、可伸縮、使用者態儲存應用程式的工具和庫。SPDK 的基礎是使用者態、輪詢、非同步、無鎖 NVMe 驅動,提供了從使用者空間應用程式到 NVMe 裝置的零拷貝、高度並行的訪問。
NVMe 的全稱是 Non-Volatile Memory Express,如果翻譯過來就是非易失性記憶體主機控制器介面規範,是一種新型的儲存裝置介面規範,用於定義硬體介面和傳輸協議,擁有比傳統 SATA SSD 的 AHCI 標準更高的讀寫效能。我們可以把 NVMe 看做一個硬體進步推動軟體革新需求的例子,隨著後續更快的儲存介質投入市場,這種推動力將更為急迫。
SPDK 專案也是一種硬體進步推動軟體革新的產物,其目標就是能夠把硬體平臺的計算、網路、儲存的最新效能進展充分發揮出來。那麼 SPDK 是如何工作的?它超高的效能實際上來自於兩項核心技術:第一個是使用者態執行,第二個是輪詢模式驅動。
首先,將裝置驅動程式碼執行在使用者態,是和執行在“核心態”相對而言的。把裝置驅動移出核心空間避免了核心上下文切換與中斷處理,從而節省了大量的 CPU 負擔,允許更多的指令週期用在實際處理資料儲存的工作上。無論儲存演算法複雜還是簡單,也無論進行去重(deduplication),加密(encryption),壓縮(compression),還是簡單的塊讀寫,更少的指令週期浪費意味著更好的整體效能。
其次,傳統的中斷式 IO 處理模式,採用的是被動的派發式工作,有 IO 需要處理時就請求一箇中斷,CPU 收到中斷後才進行資源排程來處理 IO。舉一個計程車的例子做類比,傳統磁碟裝置的 IO 任務就像計程車乘客,CPU 資源被排程用來處理 IO 中斷就像計程車。當磁碟速度遠慢於CPU 時,CPU 中斷處理資源充沛,中斷機制是能對這些 IO 任務應對自如的。這就好比是非高峰時段,計程車供大於求,路上總是有空車在掃馬路,乘客隨時都能叫到車。然而,在高峰時段,比如週五傍晚在鬧市區叫車(不用滴滴或者專車),常常是看到一輛車溜溜的近前來,而後卻發現後座已經有乘客了。需要等待多久,往往是不可預知的。相信你一定見過在路邊滯留,招手攔車的人群。同樣,當硬碟速度上千倍的提高後,將隨之產生大量 IO 中斷,Linux 核心的中斷驅動式 IO 處理(Interrupt Driven IO Process)就顯得效率不高了。
而在輪詢模式驅動下,資料包和塊得到迅速派發,等待時間最小化,從而達到低延時、更一致的延時(抖動變少)、更好的吞吐量的效果。
當然,輪詢模式驅動並不是在所有的情況下都是最高效的 IO 處理方式。對於低速的 SATA HDD,PMD 的處理機制不但給 IO 效能帶來的提升不明顯,反而浪費了 CPU 資源。
準記憶體引擎
除了採用 SPDK+ZNSSD 軟硬體結合的儲存引擎以外,為了更有效的利用記憶體,獲得更快的讀寫速度,ZNBase 在大記憶體場景下還開發了準記憶體引擎的實現。
準記憶體引擎開發的背景源自 RocksDB 的一些侷限性:
1.WAL 的單執行緒寫模式,不能充分發揮高速裝置的效能優勢;
2.讀操作時,有可能需要查詢 level 0 層的多個檔案及其他層的檔案,這也造成了很大的讀放大。尤其是當純隨機寫入後,讀幾乎是要查詢 level0 層的所有檔案,導致了讀操作的低效。
3.針對第 2 點問題,RocksDB 中依據 level 0 層檔案的個數來做前臺寫流控及後臺合併觸發,以此來平衡讀寫的效能。這又導致了效能抖動及不能發揮高速介質效能的問題。
4.合併流程難以控制,容易造成效能抖動及寫放大。
近年來,隨著動態隨機儲存器(DRAM)容量的上升和單位價格的下降,使大量資料在記憶體中的儲存和處理成為可能。相對於磁碟,記憶體的資料讀寫速度要高出幾個數量級,將資料儲存在記憶體中相比從磁碟上訪問能夠極大地提高應用的效能。
針對這一理念,準記憶體引擎設計原則如下:
1.資料儘量存放在記憶體中,充分利用記憶體的讀寫效能。
2.基於索引與資料分離儲存的思想,索引常駐記憶體。資料可以根據記憶體容量,將部分儲存到持久化儲存裝置中。
3.提升 cpu cache 命中率,通過資料塊的重構(拆解、擴容、縮容)將 Key 相鄰的 KV 資料在記憶體空間中也相鄰,以提升 key 值遍歷的速度。
4.使用非同步落盤機制,保證平滑的 IO 速率,消除 IO 瓶頸。
基於 ART 索引的檢索機制,保證資料訪問速度。ART 演算法使用基於樂觀鎖的的同步機制,讀操作不阻塞,寫操作使用版本資訊的 CAS 原子操作以及重試機制。
由於已通過 Raft Log 實現資料的故障恢復,可以去除 WAL 寫入過程。
準記憶體引擎總體處理流程如下:
1. 新插入的資料存放在 記憶體臨時區中的 Memtable 以及 Immutable 中。
2. 非同步執行緒 Mem-Flush 將 Immutable 中的資料轉存到記憶體儲存區。
3. 記憶體儲存區會盡可能佔用更多的記憶體空間,用於存放資料。使用ART 演算法索引這些資料。
4. 記憶體儲存區記憶體空間即將不足時,啟用 L1-Flush 後臺執行緒清理記憶體儲存區中的資料。
5. L1-Flush 後臺執行緒,將該記憶體儲存區中所有的 KV 資料以及範圍刪除資料進行落盤。由於資料量大且資料有序,因此,直接落盤到 L1 層。落盤前需要保證 L1 層無檔案。落盤完成後,建立 L1 層檔案向下合併的任務。
準記憶體引擎採用 ART 演算法作為主索引的實現,可以進行快速的範圍查詢,輔助使用 Hash 索引方便進行 Get 查詢。之所以使用 ART 演算法,是因為其在讀寫方面效能均優於 B+樹、紅黑樹、二叉樹,可比肩雜湊表,而 ART 演算法比雜湊表的優勢是 ART 演算法可按順序遍歷所有資料。
參見論文:The Adaptive Radix Tree: ARTful Indexing for Main-Memory Databases
總結
本文為大家介紹了 ZNBase 基於 RocksDB 的儲存引擎架構,以及 ZNBase 團隊針對 RocksDB 的侷限性,通過開發軟硬體結合的 SPDK+ZNS SSD 儲存引擎、大記憶體場景下的準記憶體引擎,大大提高了儲存引擎的讀寫效能。
關於 ZNBase 的更多詳情可以檢視:
官方程式碼倉庫:https://gitee.com/ZNBase/zn-kvs
ZNBase 官網:http://www.znbase.com/
對相關技術或產品有任何問題歡迎提 issue 或在社群中留言討論。同時歡迎廣大對分散式資料庫感興趣的開發者共同參與 ZNBase 專案的建設。
聯絡郵箱:[email protected]