看圖瞭解RocksDB

轉載自:https://yq.aliyun.com/articles/669316數據庫

它是一個高性能的Key-Value數據庫。設計了完善的持久化機制,同時保證性能和安全性。可以良好的支持範圍查詢,由於K-V記錄就是按照Key來排序的。緩存

下圖爲寫入的流程:安全

能夠看到主要的三個組成部分,內存結構memtable,相似事務日誌角色的WAL文件,持久化的SST文件。數據結構

數據會放到內存結構memtable,必定條件下觸發寫到到SST文件。寫入WAL文件是可選的,用來恢復未寫入到磁盤的memtable。併發

memtable如其名爲一種內存的數據結構。經過設置memtable的大小、總大小來控制什麼時候flush到SST文件。大部分格式的memtable不支持併發寫入,併發調用依然會依次寫入。性能

WAL全稱wirte ahead log。打開db、flush列族(一種邏輯分片機制)都會建立WAL文件,所包含的數據所有從memtable寫入SST文件後WAL文件會被歸檔。經過設置WAL上限也會觸發flush。編碼

下圖展現了讀取的層次:設計

memtable和SST文件組成數據的全集。之上是緩存層,緩存爲提高查詢性能作了分片,底層都採用hash查詢,不一樣緩存結構的區別在於熱點數據的替換邏輯。訪問數據庫時,都是訪問的打開時間點的view(我猜想一個key有不一樣時間戳的多條記錄)。除了直接查詢db,還提供了查詢快照的機制。直接訪問db時,會持有文件句柄,這樣多個SST文件合併時,已經被合併但被訪問的文件就不能被刪除。而快照機制保證了訪問過程當中文件能被刪除(我並未想明白如何作到的),不過打開期間被刪除的key的記錄還會在新合併的文件裏存在。3d

 

memtable的結構有幾種可選,本質都是排序的結構(爲了支持範圍查詢)日誌

其中之一是上圖的跳躍表,不瞭解跳躍表機制的讀者能夠簡單理解爲有序支持近似二分查找的時間複雜度爲log2(N)的結構

另一種是hash結合跳躍表,是按照key的前綴作hash,單獨訪問一個key時性能更好,範圍查詢性能會差些

 

WAL文件結構以下圖,按照寫入的順序來存儲變長的K-V,按照固定長度來分組存儲(可能一個K-V跨多個分組)的目的是便於讀取

支持幾種SST文件結構

上圖爲按照多塊來存儲的結構。每塊的K-V都是有序的,而多塊也是有序的。文件中包含元數據相關的信息,包括數據壓縮字典、過濾器等。會按照數據塊所屬的K-V範圍來建立索引,爲提高查詢性能會給索引分片。

另一種結構是每一個K-V來存儲。它的索引比較特殊,由hash結構和二進制查找緩存兩部分組成。依然按照key的前綴作hash,若是桶對應的K-V記錄不多,則直接指向第一個key(有多個key屬於該桶)的記錄位置。若是屬於桶的K-V記錄多於16條,或者包含多於一個前綴的記錄,則先指向二進制查找緩存(先二分查找),然後指向第一個key的記錄位置。

 

隨着K-V的寫入,會生成不少的SST文件。這部分文件須要被合併到一塊兒,從而下降打開文件數量,而且移除已經不存在的記錄。

介紹合併以前先了解sorted runs的概念。一個sorted run能夠理解爲一個時間段的全部數據,不一樣sorted run會覆蓋不一樣時間段。一般會給sorted run編號,並稱做levelX,時間範圍越早的sorted run編號越高(level0的數據最新,也是memtable,嚴格意義上說不屬於sorted run,由於不必定有序)。

 

rocksdb主要提供了兩類方式,通用合併(有時亦稱做tiered)與leveled合併(rocksdb的默認方式)。它們的最主要區別在於頻度,後者會更積極的合併小的sorted run到大的,而前者更傾向於等到二者大小至關後再合併。

上圖爲通用合併過程

 

我把通用合併簡單理解爲更簡單粗暴的合併,能夠儘可能下降磁盤的寫入,但會增大讀取,須要更大的臨時空間(極端時須要兩倍數據容量的磁盤空間)。遵循的一個規則是「合併結果放到可能最高的level」。是否觸發合併是依據設置的空間比例參數。
size amplification ratio = (size(R1) + size(R2) + ... size(Rn-1)) / size(Rn)

上圖爲level合併過程

每一個level有相應的目標大小,超出後會觸發本level與下一level的文件合併到一塊兒。合併是能夠併發執行的(L0到L1比較特殊須要先分片後才能並行)。

 

總結下rocksdb作了哪些設計來知足預期的使用場景。全部記錄在業務上是有序的,對key的查詢其實會執行相似二分查找。持久化是經過寫入有序文件來實現的。高性能的寫入是經過先寫入內存結構來保證的(寫滿的內存結構刷到持久化文件)。提供了level機制對數據作分層,優先查詢最新寫入的level從而提高查詢性能。針對查詢有常見的緩存、索引機制,也有壓縮、編碼機制來節省存儲空間。