Tair儲存引擎之一Leveldb中資料的儲存思想

2021-06-22 18:38:50 字數 3482 閱讀 4431

tair 是**自己開發的乙個分布式 key/value 儲存引擎. tair 分為持久化和非持久化兩種使用方式. 非持久化的 tair 可以看成是乙個分布式快取. 持久化的 tair 將資料存放於磁碟中. 在最新版本的tair trunk中目前實現了以下4種儲存引擎。

非持久化:mdb

持久化:fdb、kdb和 ldb

分別基於四種開源的key/value資料庫:memcached、firebird、kyoto cabinet和leveldb。其中memcached和firebird是關係型儲存資料庫,而kyoto cabinet和leveldb是nosql資料庫。

這裡我研究的是google開源的快速輕量級的單機kv儲存引擎leveldb的實現方式。

leveldb的基本特性:

限制:

說到儲存引擎我立刻想到mysql的兩大常用儲存引擎myisam和innodb,關係型資料庫的資料儲存在邏輯的表空間中,而資料庫索引一般都是用的b/b+樹系列,包括mysql及nosql中的mongodb。那為什麼在磁碟中要使用b+樹來進行檔案儲存呢?首先磁碟本身是乙個順序讀寫快,隨機讀寫慢的系統,磁碟的效能主要受限於磁碟的尋道時間,那麼如果想高效的從磁碟中找到資料,就需要減少尋道次數,也就是儘量減少磁碟的io次數,而磁碟io次數又取決於資料在磁碟上的組織方式。b+樹是一種專門針對磁碟儲存而優化的n叉排序樹,以樹節點為單位儲存在磁碟中,從根開始查詢所需資料所在的節點編號和磁碟位置,將其載入到記憶體中然後繼續查詢,直到找到所需的資料。b+樹的儲存方式使得具有良好的查詢、插入和修改的效能,但如果有大量的更新插入刪除等綜合寫入,最後會因為需要迴圈利用磁碟塊而出現較多的隨機io,大量時間消耗在磁碟尋道時間上,如果是乙個執行時間很長的b+樹,那麼幾乎所有的請求,都是隨機io。因為磁碟塊本身已經不再連續,很難保證可以順序讀取。這是b+樹在磁碟結構中最大的問題。

那麼如何能夠解決這個問題呢?

目前主流的思路有以下幾種

(1)放棄部分讀效能,使用更加面向順序寫的樹的結構來提公升寫效能。

這個類別裡面,從資料結構來說,就我所知並比較流行的是兩類,

一類是cola(cache-oblivious look ahead array),代表應用是tokudb。

一類是lsm tree(log-structured merge tree)或sstable,代表的應用有cassandra、hbase、leveldb 及眾多類bigtable儲存。

(2)使用ssd,讓尋道成為往事。

leveldb的資料儲存方式採用的是lsm(log-structured-merge)的實現方法,簡單來說就是將原來的直接維護索引樹變為增量寫的方式,這樣能夠保證對磁碟的操作是順序的。具體的lsm實現可以看」the log-structured merge-tree「這篇**。log-structured的思想最早由 rosenblum和ousterhout於2023年在研究日誌結構的檔案系統時提出。他們將整個磁碟就看做是乙個日誌,在日誌中存放永久性資料及其索引,每次都新增到日誌的末尾;通過將很多小檔案的訪問轉換為連續的大批量傳輸,使得對於檔案系統的大多數訪問都是順序性的,從而提高磁碟頻寬利用率,故障恢復速度快。 o'neil等人受到這種思想的啟發,借鑑了log不斷追加(而不是修改)的特點,結合b-tree的資料結構,提出了一種延遲更新,批量寫入硬碟的資料結構lsm-tree及其演算法。lsm-tree努力地在讀和寫兩方面尋找乙個平衡點以最小化系統的訪問效能的開銷,特別適用於插入頻率遠大於查詢頻率的應用場景。

lsm樹可以看作是乙個n階合併樹。資料寫操作(包括插入、修改、刪除)都在記憶體中進行,並且都會建立乙個新記錄(修改會記錄新的資料值,而刪除會記錄乙個刪除標誌),這些資料在記憶體中仍然還是一棵排序樹,當資料量超過設定的記憶體閾值後,會將這棵排序樹和磁碟上最新的排序樹合併。當這棵排序樹的資料量也超過設定閾值後,和磁碟上下一級的排序樹合併。合併過程中,會用最新更新的資料覆蓋舊的資料(或者記錄為不同版本)。

在需要進行讀操作時,總是從記憶體中的排序樹開始搜尋,如果沒有找到,就從磁碟上的排序樹順序查詢。

在lsm樹上進行一次資料更新不需要磁碟訪問,在記憶體即可完成,速度遠快於b+樹。當資料訪問以寫操作為主,而讀操作則集中在最近寫入的資料上時,使用lsm樹可以極大程度地減少磁碟的訪問次數,加快訪問速度。

在了解lsm後,需要知道基於lsm結構的儲存引擎的資料有什麼儲存特點,下面簡單總結幾點。

(1)leveldb中各個儲存檔案是分層的,新插入的值放在記憶體表中,稱為memtable(通過skiplist實現),該錶寫滿時變為immutable table,並建立新的memtable接收寫操作,而immutable table是不可變更的,會通過compact過程寫入level0,其中的資料被組織成sstable的資料檔案,所以,同時最多會存在兩個memtable(正在寫的memtable和immutable memtable)。level0的檔案會通過後台的compact過程寫入level1,level1的檔案又會寫入level2,依次類推,這是」merge dump「的流程。

(2)leveldb在寫操作時只是單純的在檔案末尾增加一條記錄而不會改動原來的資料,更新key直接插入一條新的key/value資料(即key已經存在),而刪除操作可以看成插入一條value為空的資料,為了區分真實kv資料和刪除操作的mock資料,使用valuetype來標識:

enum valuetype ;

除此之外,leveldb每次更新(put/delete)操作都擁有乙個版本,由sequncenumber來標識,整個db有乙個全域性值儲存著當前使用到的sequncenumber。sequncenumber在leveldb有重要的地位,key的排序,compact以及snapshot都依賴於它。leveldb內部按照key非遞減,sequncenumber非遞增,valuetype非遞增排序,這樣查詢時便可以找到key對應的最新值,如果type位ktypedeletion則不存在。

(3)考慮節約空間,leveldb對key的儲存進行字首壓縮後再寫入sstable,每個entry中會記錄key與前乙個key字首相同的位元組(shared_bytes)以及自己獨有的位元組(unshared_bytes)。讀取時,對block進行遍歷,每個key根據前乙個key以及shared_bytes/unshared_bytes可以構造出來。

(4)最重要的一點:由於tair是根據hash分割槽的,而prefix系列的介面是根據prefixkey去hash的。所以能確保擁有相同prefix的key在同一臺伺服器上。

首先講述了leveldb的基本特性,然後簡單講解了leveldb儲存結構的**lsm的基本思想和適用場景,最後總結了幾點leveldb中儲存資料的特點,實際的儲存結構較複雜,有記憶體儲存結構和持久化儲存結構。下一步繼續探索leveldb的儲存過程。

(1)tair官網介紹

(2)leveldb官網介紹

(3)日誌結構的合併樹 the log-structured merge-tree

(4)從lsm-tree、cola-tree談到stackoverflow、osqa

(5)為什麼檔案儲存要選用b 樹這樣的資料結構?

儲存引擎揭秘 基本結構之一 記錄

儲存引擎揭秘 基本結構之一 記錄 本週我將發表一系列 sql server 中用來儲存資料和跟蹤分配的基本結構。大部分文章其實當初我在 teched2006 上開博時便發表過,但是現在我想更清晰地描述它,並使用 dbcc page 來檢查各種結構。那麼,什麼是記錄?簡單地說,一條記錄就是物理儲存的表...

MySQL(一)儲存引擎

mysql資料庫作為一款開源免費的關係型資料庫受到了國內很多開發人員歡迎,下面想把mysql資料庫的一些知識點紀錄下來,對於自己也是乙個再學習再記憶的過程 外掛程式式的儲存引擎是mysql資料庫最重要的特點之一,它支援了myissam,innodb,bdb,memory,merge等多種儲存引擎,開...

MSQL儲存引擎(一)

default 支援並啟用,並且為預設引擎 yes 支援並啟用 no 不支援 常見的四種儲存引擎 myisam,memory,innodb,archive myisam 既不支援事務,也不支援外來鍵,對事務完整性沒有要求或者,以select insert為主的應用可以使用這個引擎來建立表。myisa...