LSM樹(Log-Structured Merge Tree)存儲引擎
代表數據庫:nessDB、leveldb、hbase等
核心思想的核心就是放棄部分讀能力,換取寫入的最大化能力。LSM Tree ,這個概念就是結構化合並樹的意思,它的核心思路其實非常簡單,就是假定內存足夠大,因此不需要每次有數據更新就必須將數據寫入到磁盤中,而可以先將最新的數據駐留在磁盤中,等到積累到最后多之后,再使用歸並排序的方式將內存內的數據合並追加到磁盤隊尾(因為所有待排序的樹都是有序的,可以通過合並排序的方式快速合並到一起)。
日志結構的合並樹(LSM-tree)是一種基於硬盤的數據結構,與B-tree相比,能顯著地減少硬盤磁盤臂的開銷,並能在較長的時間提供對文件的高速插入(刪除)。然而LSM-tree在某些情況下,特別是在查詢需要快速響應時性能不佳。通常LSM-tree適用於索引插入比檢索更頻繁的應用系統。Bigtable在提供Tablet服務時,使用GFS來存儲日志和SSTable,而GFS的設計初衷就是希望通過添加新數據的方式而不是通過重寫舊數據的方式來修改文件。而LSM-tree通過滾動合並和多頁塊的方法推遲和批量進行索引更新,充分利用內存來存儲近期或常用數據以降低查找代價,利用硬盤來存儲不常用數據以減少存儲代價。
磁盤的技術特性:對磁盤來說,能夠最大化的發揮磁盤技術特性的使用方式是:一次性的讀取或寫入固定大小的一塊數據,並盡可能的減少隨機尋道這個操作的次數。
轉自:http://blog.csdn.net/dbanote/article/details/8897599
LSM樹是Hbase里非常有創意的一種數據結構,它和傳統的B+樹不太一樣,下面先說說B+樹。
1 B+樹
相信大家對B+樹已經非常的熟悉,比如Oracle的普通索引就是采用B+樹的方式,下面是一個B+樹的例子:
根節點和枝節點很簡單,分別記錄每個葉子節點的最小值,並用一個指針指向葉子節點。
葉子節點里每個鍵值都指向真正的數據塊(如Oracle里的RowID),每個葉子節點都有前指針和后指針,這是為了做范圍查詢時,葉子節點間可以直接跳轉,從而避免再去回溯至枝和跟節點。
B+樹最大的性能問題是會產生大量的隨機IO,隨着新數據的插入,葉子節點會慢慢分裂,邏輯上連續的葉子節點在物理上往往不連續,甚至分離的很遠,但做范圍查詢時,會產生大量讀隨機IO。
對於大量的隨機寫也一樣,舉一個插入key跨度很大的例子,如7->1000->3->2000 ... 新插入的數據存儲在磁盤上相隔很遠,會產生大量的隨機寫IO.
從上面可以看出,低下的磁盤尋道速度嚴重影響性能(近些年來,磁盤尋道速度的發展幾乎處於停滯的狀態)。
2 LSM樹
為了克服B+樹的弱點,HBase引入了LSM樹的概念,即Log-Structured Merge-Trees。
為了更好的說明LSM樹的原理,下面舉個比較極端的例子:
現在假設有1000個節點的隨機key,對於磁盤來說,肯定是把這1000個節點順序寫入磁盤最快,但是這樣一來,讀就悲劇了,因為key在磁盤中完全無序,每次讀取都要全掃描;
那么,為了讓讀性能盡量高,數據在磁盤中必須得有序,這就是B+樹的原理,但是寫就悲劇了,因為會產生大量的隨機IO,磁盤尋道速度跟不上。
LSM樹本質上就是在讀寫之間取得平衡,和B+樹相比,它犧牲了部分讀性能,用來大幅提高寫性能。
它的原理是把一顆大樹拆分成N棵小樹, 它首先寫入到內存中(內存沒有尋道速度的問題,隨機寫的性能得到大幅提升),在內存中構建一顆有序小樹,隨着小樹越來越大,內存的小樹會flush到磁盤上。當讀時,由於不知道數據在哪棵小樹上,因此必須遍歷所有的小樹,但在每顆小樹內部數據是有序的。
以上就是LSM樹最本質的原理,有了原理,再看具體的技術就很簡單了。
1)首先說說為什么要有WAL(Write Ahead Log),很簡單,因為數據是先寫到內存中,如果斷電,內存中的數據會丟失,因此為了保護內存中的數據,需要在磁盤上先記錄logfile,當內存中的數據flush到磁盤上時,就可以拋棄相應的Logfile。
2)什么是memstore, storefile?很簡單,上面說過,LSM樹就是一堆小樹,在內存中的小樹即memstore,每次flush,內存中的memstore變成磁盤上一個新的storefile。
3)為什么會有compact?很簡單,隨着小樹越來越多,讀的性能會越來越差,因此需要在適當的時候,對磁盤中的小樹進行merge,多棵小樹變成一顆大樹。
關於LSM Tree,對於最簡單的二層LSM Tree而言,內存中的數據和磁盤中的數據merge操作,如下圖
下面說說詳細例子:
LSM Tree弄了很多個小的有序結構,比如每m個數據,在內存里排序一次,下面100個數據,再排序一次……這樣依次做下去,就可以獲得N/m個有序的小的有序結構。
在查詢的時候,因為不知道這個數據到底是在哪里,所以就從最新的一個小的有序結構里做二分查找,找得到就返回,找不到就繼續找下一個小有序結構,一直到找到為止。
很容易可以看出,這樣的模式,讀取的時間復雜度是(N/m)*log2N 。讀取效率是會下降的。
這就是最本來意義上的LSM tree的思路。那么這樣做,性能還是比較慢的,於是需要再做些事情來提升,怎么做才好呢?
LSM Tree優化方式:
a、Bloom filter: 就是個帶隨即概率的bitmap,可以快速的告訴你,某一個小的有序結構里有沒有指定的那個數據的。於是就可以不用二分查找,而只需簡單的計算幾次就能知道數據是否在某個小集合里啦。效率得到了提升,但付出的是空間代價。
b、compact:小樹合並為大樹:因為小樹他性能有問題,所以要有個進程不斷地將小樹合並到大樹上,這樣大部分的老數據查詢也可以直接使用log2N的方式找到,不需要再進行(N/m)*log2n的查詢了
更詳細的可以參考:http://weakyon.com/2015/04/08/Log-Structured-Merge-Trees.html