阿里资深技术专家:优秀的数据库存储引擎应具备哪些能力?
導讀
本文作者是阿里巴巴OLTP數據庫團隊資深技術專家——曲山。作為自研高性能、低成本存儲引擎X-Engine的負責人,曲山眼中的優秀關系型數據庫存儲引擎應該具備哪些能力呢?
正文
數據庫內核按層次來分,就是兩層:SQL & Storage。SQL Layer負責將你輸入的SQL statement通過一系列步驟(parse/resolve/rewrite/optimize…)轉換成物理執行計劃,同時負責計劃的執行,執行計劃通常是一顆樹的形式,其中樹的葉子節點(執行器算子)部分往往負責單表的數據操作,這些操作算子就要在storage layer來執行了。
因此,一個數據庫存儲引擎的主要工作,簡單來講就是存取數據,但是前提是保證數據庫的ACID(atomicity/consistency/isolation/durability)語義。存儲引擎對外提供的接口其實比較簡單,主要就是數據寫入/修改/查詢,事務處理(start transaction/commit/rollback…),修改schema對象/數據字典(可選), 數據統計,還有一些周邊的運維或數據導入導出功能。
僅僅從功能上來說,要實現一個存儲引擎似乎并不困難,如今也有很多Key-Value Store搖身一變就成為了數據庫存儲引擎,無非是加上一套事務處理機制罷了。但是作為數據庫的底盤,一個成熟的存儲引擎必須要考慮效率,如何高效(性能/成本最大化)的實現數據存取則成了在設計上做出種種權衡的主要考量。可以從存儲引擎的幾個主要組件來討論:
數據組織
數據在內存和磁盤中的組織方式很大程度上決定了存取的效率,不同的應用場景選擇也不同,典型的如:
所以做存儲引擎,一開始就要面臨選擇何種存儲格式的問題。即便選定了大類,每種格式中也有無數的細節需要考慮,每種數據類型的字段如何編碼(Encoding),行存中null/not null如何存儲,是否需要列索引加快project operation,是否需要對列值進行重排,列存如何進行數據壓縮,等等,都要存儲空間和存取速度中做平衡。
現代數據庫為了應對復雜的應用場景,往往使用不只一種存儲格式,比如Oracle有In-memory Column Store在內存中將行存的頁面轉換為列存方式的page,用來加速復雜查詢。
當數據選定存儲格式以后,還要選擇數據在磁盤和內存中的聚集方式。以按行存儲為例,大部分存儲引擎使用固定大小的頁面(page)來存儲連續的若干行。當然,數據行如何連續排列,有堆表(隨機)和索引組織表(按索引序)兩種,現在較為流行的LSM-Like的存儲引擎使用不定大小的頁面(稱為DataBlock),只支持按主鍵索引序聚集;這兩種方式主要區別在于前者被設計為可更新的,每個page中會留有空間,后者是只讀的,數據緊密存儲不帶padding,便于壓縮。兩者的區別實際上是因為事務處理機制有較大的區別導致的,后面再論。
對于In-Memory Database來說,數據組織的方式會有較大區別,因為不需要在內存和持久化存儲中交換數據,內存中一般不會使用page形式,而是直接使用索引存儲結構(比如B+Tree)直接索引到記錄(tuples),無需page這一層間接引用,減少cpu cache miss。
緩存管理
緩存的粒度一般是page,關鍵在于緩存替換算法。目前用的比較廣泛的LRU,LFU,ARC..以及各種變種的算法都有在數據庫中使用。另外還有一個是如何更有效的管理內存的問題,這點上,定長的page會比不定長的更有優勢。
當然還要考慮各種query pattern對cache的影響,如果單行查詢較多,選用更細粒度(比如row)的cache會更有效率,但是淘汰的策略會更復雜,很多新的研究開始嘗試引入機器學習的方法來優化cache淘汰算法,以及有效的管理cache.
事務處理
存儲引擎之核心,保證數據庫的ACID。要保證D,大家的做法差不多,都是寫WAL(Write Ahead Log)來做recovery,關鍵是如何高效的實現ACI,也就是所謂的多版本并發控制(MVCC)機制。
MVCC的完整實現比較復雜,暫不詳細闡述,這里面的關鍵在于如何處理并發執行過程中的數據沖突(data race),包括寫寫沖突,讀寫沖突;因為數據庫的負載一般是讀多寫少的,要做到高效,只讀事務不能被讀寫事務阻塞,這就要求我們的寫不能直接去更新當前的數據,而是要有一套維護多版本數據的能力,當前的存儲引擎管理多版本數據的辦法無非兩種:
前一種稱為ARIES算法比大多數主流數據庫存儲引擎使用,后一種稱為LSM-Tree的結構也被很多新存儲引擎使用,受到越來越多的關注。
Catalog
與KV store有區別的是,數據庫是有嚴格的schema的,所以多數存儲引擎中的記錄都是有結構的,很多KV store在作為數據庫存儲引擎時,都是在中間做一層轉換,將上層處理的tuples以特定的編碼方式轉換為binary key-value,寫入KVStore,并在讀取到上層后,依靠schema解釋為tuples格式供上層處理。
這種方法當然可以工作,但是諸多優化無法實施:a. 數據迭代必須是整行,即便只需要其中一列,序列化/反序列化開銷是免不了的。b. project和filter的工作無法下放到存儲層內部進行處理; c. 沒有列信息,做按列編碼,壓縮也不可能。d. schema change只能暴力重整數據… 因此要做到真正的高效,越來越多的存儲引擎選擇完全感知schema,存儲細微結構。
總結
以上所探討的,還只是單機數據庫的存儲引擎幾個大的問題,而現代數據庫對存儲引擎提出了更高的要求,可擴展,高可用已經成為標配,現在要考慮的是如何給你的存儲引擎加上分布式的能力,而這又涉及到高可用一致性保證,自動擴展,分布式事務等一系列更為復雜的問題,這已遠超出本文的范疇,需要另開篇章。
最后介紹下我們正在開發的阿里自研分布式數據庫X-DB,其中的存儲引擎就使用了我們自研的X-Engine。X-Engine使用了一種對數據進行分層的存儲架構,因為目標是面向大規模的海量數據存儲,提供高并發事務處理能力和盡可能降低成本。
我們根據數據訪問頻度(冷熱)的不同將數據劃分為多個層次,針對每個層次數據的訪問特點,設計對應的存儲結構,寫入合適的存儲設備。X-Engine使用了LSM-Tree作為分層存儲的架構基礎,并在這之上進行了重新設計。
簡單來講,熱數據層和數據更新使用內存存儲,利用了大量內存數據庫的技術(Lock-Free index structure/append only)提高事務處理的性能,我們設計了一套事務處理流水線處理機制,把事務處理的幾個階段并行起來,極大提升了吞吐。而訪問頻度低的冷(溫)數據逐漸淘汰或是合并到持久化的存儲層次中,結合當前豐富的存儲設備層次體系(NVM/SSD/HDD)進行存儲。
我們對性能影響比較大的compaction過程做了大量優化,主要是拆分數據存儲粒度,利用數據更新熱點較為集中的特征,盡可能的在合并過程中復用數據,精細化控制LSM的形狀,減少I/O和計算代價,并同時極大的減少了合并過程中的空間放大。同時使用更細粒度的訪問控制和緩存機制,優化讀的性能。當然優化是無止境的,得益于豐富的應用場景,我們在其中獲得了大量的工程經驗。
X-Engine現在已經不只一個單機數據庫存儲引擎,結合我們的X-Paxos(分布式強一致高可用框架), GMS(分布式管理服務), 和X-Trx(分布式事務處理框架),已經演變為一個分布式數據庫存儲系統。
?
原文鏈接
本文為云棲社區原創內容,未經允許不得轉載。
總結
以上是生活随笔為你收集整理的阿里资深技术专家:优秀的数据库存储引擎应具备哪些能力?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 云栖专辑 | 阿里开发者们的第10个感悟
- 下一篇: 90后ACE成长记——从偏居一隅小城里走