1. 程式人生 > >論文閱讀-The Log-Structured Merge-Tree (LSM-Tree)

論文閱讀-The Log-Structured Merge-Tree (LSM-Tree)

論文閱讀-The Log-Structured Merge-Tree (LSM-Tree)

0x00 論文原文

The Log-Structured Merge-Tree (LSM-Tree)

0x01 摘要

這兩天看了下LSM樹的內容,網上的博文大多講的不太詳細,但都有提到這篇論文。本著嚴謹的態度,就找時間啃了下此論文,在這裡對核心內容做一些記錄。

0x02 論文摘要

高效能的交易系統通常會為一次交易就插入若干條記錄到歷史表,使其可追溯。這就使得高效的實時索引十分重要。LSM樹是一個基於磁碟的資料結構,主要用於為那些高概率插入和刪除的記錄提供低成本的索引。

LSM使用了一個演算法來延遲批處理索引變更,然後類似歸併排序的方式串聯起一個基於記憶體的元件和若干基於磁碟的元件上面的所有變更資訊。該演算法相比於傳統的B樹訪問方式大大減少磁碟臂的移動開銷。

由於索引搜尋需要立刻響應,這會在某些場景降低IO效率,所以LSM樹在索引寫入佔比大大超過索引查詢的場景中最適用,如歷史表和日誌檔案。

0x03 介紹

3.1 五分鐘法則

磁碟頁的訪問頻率超過每60秒1次,我們就可以通過購買(擴充)記憶體快取空間來將磁碟頁儲存到記憶體,以減少磁碟IO帶來的系統開銷。

3.2 原文中例二

一個在具有高插入量的歷史記錄表上的索引,可以證明這樣的一個索引將會使TPC應用的磁碟開銷加倍:
一個建立在 AccountId + Timestamp之上的聯合索引。他對於支援類似以下的近期賬戶行為資訊高效查詢至關重要:

// 搜尋某個時間之後的賬戶Id的所有歷史行為資料
(1.1) Select * from History where History.Acct-ID = %custacctid and History.Timestamp > %custdatetime;

這個例子中的場景,搜尋遠遠少於插入(正常人不會像存取款那樣頻繁地檢視自己的賬戶相關行為資訊)。因為每次搜尋Acct-ID基本都是隨機的,基本每次都需要讀取一個磁碟頁。但根據五分鐘法則又不能將這些磁碟頁放入記憶體,因為這些磁碟頁讀取大約相隔2300秒,也就是說這些訪問都是磁碟IO。原文中的資料展現了商業系統中最常用的資料結構B+樹索引帶來的巨大的IO和磁碟開銷。

然後又提到LSM樹可以在插入索引時減少磁碟動作,以致開銷少一個量級。LSM樹使用的演算法,可以延遲和批處理索引變更(這一點十分重要),並且以一種特別高效的、類似歸併排序的方式將這些變更遷移到磁碟。LSM樹結構還支援其他索引操作,例如刪除,更新,甚至是長延遲的查詢動作(只不過哪些需要立刻返回的查詢需要相對多的開銷)。LSM特別適合前面例子那樣搜尋遠遠少於插入的場景。這種場景下,最重要的就是減少索引插入時的開銷。當然,也需要維護一個索引,因為搜尋行為不可能全是順序的。

0x04 LSM樹演算法的兩大元件

4.1 元件介紹

LSM樹由兩個或更多的類樹元件組成。本章只討論最簡單的2個元件的情況。同時,這裡會用LSM樹來探討前面的賬戶歷史記錄例子。

LSM樹2元件
一棵擁有兩個元件的LSM樹擁有兩部分:

  • 一個較小的位於記憶體的元件,就是上圖中的C0 tree
  • 一個較大的位於磁碟的元件,就是上圖中的C1 tree

儘管C1樹常駐磁碟,但他的常被訪問的磁碟頁會被保留在記憶體中(未在圖中展示)。

歷史記錄表的資料每生成一行新記錄流程如下:

  1. 首先向順序日誌檔案中寫一條用於恢復這次插入行為的日誌記錄
  2. 該行資料的索引被插入到常駐記憶體的 C0 樹中
  3. 會適時地將這些C0樹上的資料遷移到磁碟上的C1樹中
  4. 每個索引的搜尋過程都是先C0後C1

上述C0->C1的資料遷移過程有一定時間時延,這就暗含了因為系統崩潰導致沒刷到C1中的那部分索引資料可恢復的需求。

4.2 元件合併

4.2.1 C0合併到C1簡述

上述C0樹寫入是無IO開銷的,但是C0位於記憶體,成本遠高於磁碟,這就需要有一種高效的刷盤方式到C1。

LSM樹採用的方法是當C0樹上的插入的資料幾乎達到指定的閾值時,有一個持續迴圈的合併程序服務會刪除C0樹上的一些連續segment段,將他們合併到磁碟中的C1樹。下圖展示了這個程序:

C0MergeToC1

4.2.2 C1樹結構

LSM中C1樹具有與B樹類似的目錄結構,但C1樹與B樹不同的是C1樹的所有節點都是滿的。並且為了更有效的利用磁臂,做了以下優化:

大小 描述 用途
單頁塊 4KB 根節點;每個層級上的單頁節點 單頁節點被用在匹配索引查詢中,以最小化快取需求
多頁塊 256KB 根目錄下的每個層級上的單頁節點序列會被打包,然後一起放入連續的多頁磁碟塊中(囊括了根節點以下的節點),利於磁碟順序訪問 多頁塊IO,在滾動合併期間、大範圍的範圍搜尋中被使用

4.2.3 C0滾動合併到C1簡述

滾動合併的行為包括一系列的合併步驟:

  1. 先讀取包含C1樹的葉節點的多頁塊,這會使得C1中的一系列節點條目駐留到快取
  2. 然後每次合併都會去讀取已經被快取的C1樹的一個磁碟頁大小的葉節點
  3. 接著將第二步中讀取到的C1樹葉節點上的條目與C0樹的葉節點條目進行合併,並減少C0樹的大小
  4. 合併完成後,會為C1樹建立一個已合併的新葉節點(在快取中,填滿後被刷入磁碟)

4.2.4 empty block和filling block

  • empty block
    那些在合併前,已快取、且包含舊的C1樹節點的多頁塊被稱為empty block,意味著他們會被清空、移除。
  • filling block
    而新的葉節點被寫入與舊的多頁塊不同的已快取的多頁塊,被稱為filling block,意味著他們會被填滿。當filling block被C1樹新合併的葉節點填滿時,該多頁塊會被寫入一個磁碟上一個新的空閒區域。注意,新合併的塊會被寫入新的磁碟位置,這使得舊的塊不會被覆蓋。這樣的好處是可在系統崩潰時快速恢復。

上面的圖中下方圓圈內就是新的多頁block,包含了merge結果。隨後的合併步驟持續將C0和C1元件的增加的索引值段彙集在一起,直到達到最大值,此時滾動合併又從最小值再次開始。

C1的父目錄節點也會被快取到記憶體,被更新以反映新葉子節點的結構變動,但通常會在快取中保留更長的時間以減少IO;C1上舊的葉節點會在合併完成後變為非法,然後被從C1目錄中刪除。為了縮短恢復時重建所需時長,會定期進行合併過程的checkpoint,這會將所有緩衝的資訊強制刷到磁碟。

4.3 LSM樹元件建立流程

4.3.1 C0樹結構

前面說過磁碟上的C1樹是類B樹,但C0樹不同,他不是類B樹。因為C0樹不會都是在記憶體不會放在磁碟,所以節點可以任意大小不必考慮磁碟頁大小而設計。這樣一來,就沒有必要為了減少IO而犧牲CPU效率,從而刻意地將樹高度壓得很低。比如B樹為了這麼做,就讓樹每一層非常寬,每個節點內部的關鍵字特別多,需要順序查詢。這種情況下,2-3樹或AVL樹效率高於B樹,可作為C0樹的資料結構。

4.3.2 C0滾動合併到C1詳解

首次從C0樹到C1樹的過程如下:

  1. 當增長中的C0樹第一次達到閾值的時候
  2. 最靠左的一系列條目會以高效批量形式從C0樹中刪除
  3. 然後被重組到C1樹(按key遞增順序),將被完全填滿
  4. 連續的C1樹的葉節點會按從左到右的順序,首先被放置到常駐記憶體的多頁塊內的若干初始頁上
  5. 持續上一步直到該多頁塊被填滿
  6. 然後該多頁塊被刷到磁碟,成為C1樹葉節點層的第一部分,常駐磁碟
  7. 隨著這些連續的葉節點新增的過程,一個C1樹的目錄節點結構會在記憶體快取中被建立(這些上層目錄節點被存在單獨的多頁塊快取或單獨的頁快取中,為了更高效利用記憶體和磁碟。其中還包含分隔點索引,可以將訪問精確匹配導向某個下一層級的單頁節點而不是多頁塊,類似B樹。這樣一來,我們就可在滾動合併或長範圍搜尋時使用多頁塊,而在索引精確匹配訪問時使用單頁節點)
  8. 在發生如下情況時,C1的目錄節點會被強制刷盤
    • 包含目錄節點的多頁塊快取滿了 -> 只有該多頁塊會被刷盤
    • 根節點分裂,增加了C1樹的深度(大於2) -> 所有多頁塊刷盤
    • checkpoint被執行-> 所有多頁塊刷盤

4.3.3 滾動合併與概念遊標

可以把擁有兩個元件的LSM樹的滾動合併的過程,想象為擁有一個概念上的遊標,他在C0樹和C1樹的等值key value間緩慢穿梭移動,將C0樹的索引資料取出放入磁碟上的C1樹中。

這個滾動合併遊標在C1樹的葉子節點和上層目錄都有個位置點。每個層級上,所有C1樹的正在合併的多頁塊通常會被分割為兩塊,且為了併發訪問他們分別擁有整數個頁大小的C1樹節點。這兩個型別塊如下:

  1. empty block
    其條目已經耗盡,但保留了遊標尚未到達的一些資訊
  2. filling block
    反映出此刻的合併結果

一旦需要將所有快取的節點刷入磁碟,所有層級的快取資訊必須被寫入新的磁碟位置,這些位置會被反映到上層的目錄資訊,還會生成一系列的日誌條目可用來做恢復。

不久之後,當快取中的filling block(存放了C1樹某些層級)被填滿時,需要再次被刷盤,此時會存入一個新的磁碟位置。在恢復期間需要的舊資訊不會被覆寫磁碟,只有當足夠的新資訊被寫入後才會失效。原文第四部分詳述了關於滾動合併的資訊,提到了併發和可恢復的設計。(我其實覺得已經夠詳細夠晦澀了,可能是我水平太低了- -|)

4.3.4 廢棄塊重用

LSM樹關於C1樹的某一特定層級節點的滾動合併過程,會達到相對較高的rate,所有讀寫都在多頁塊中,這是關於效率方面的重要考慮。通過消除磁碟尋道時間和旋轉時延,我們希望效率遠超過隨機頁IO(如B樹插入時)。新的多頁塊寫入使用新的磁碟空間,這就暗含了需要能重用廢棄的塊。這些使用記錄可以放入到一個記憶體表中。舊的多頁塊被廢棄然後被作為單獨的單元被重用,而恢復是由checkpoint保證。

  • Log-Structured檔案系統中,對廢舊塊的重用包括了很大的IO開銷,因為塊通常僅為部分釋放,因此重用時需要對塊進行讀/寫。
  • 而在LSM樹中,塊會在滾動合併中被完全釋放,不存在額外IO。

4.4 LSM樹索引查詢

4.4.1 搜尋原則

當一個需要立刻返回的精確匹配查詢或是範圍查詢在LSM樹的索引上執行時,會先在C0樹執行搜尋值,然後搜C1樹。這暗含著少許額外的CPU開銷(相對於B樹來說),因為分別去兩棵樹目錄進行搜尋。

LSM樹多元件
如上圖,考慮多個元件的LSM樹,擁有C0, C1, C2 … Ck,這樣一個遞增的索引樹結構。其中C0是駐留在記憶體的,而且他元件都在磁碟。這種情況下,每當Ci-1 條目達到閾值時,每個(Ci-1,Ci)之間的非同步滾動合併過程會從較小的元件中移動條目到較大的元件。這個結論很重要,務必牢記。

LSM有一個規則,即為了保證LSM中所有條目都被檢查到,就必須讓每個精確匹配或範圍查詢要訪問每個Ci元件的索引結構。然而,有一些可能的優化方式,可使得此搜尋範圍限制在元件的初始子集。請看下一節。

4.4.2 搜尋優化

  1. 如果記錄的生成邏輯就能保證索引唯一性,比如時間戳,那麼在較小的一個Ci元件內搜尋到結果就可以直接停止搜尋直接返回。
  2. 再比如,搜尋條件中使用了最近的時間戳,我們可以限制搜尋範圍為那些還沒有移動到最大元件的記錄所處的序號小的元件上。當合並遊標在(Ci,Ci + 1)對中迴圈徘徊時,我們通常有理由保留Ci中那些最近插入的條目(比如在最近τi秒內),而只允許那些較舊的條目移動到Ci+1中。
  3. 在最頻繁的查詢指向最近插入的值的這種場景中,許多搜尋都可在C0樹中就完成,這樣就使得C0樹完全發揮了了自己的記憶體快取價值。這是十分重要的效能優化策略。舉個例子,被用作短期事務UNDO日誌索引,在中止事件中被訪問,在建立這些索引後會有大比例是訪問短期內的資料,所以我們可以預期大多數這樣的索引會駐留在記憶體中。
  4. 通過跟蹤每個事務的開始時間,我們可以保證在最後的τ0秒內啟動事務的所有日誌,例如,將在元件C0中找到,而無需搜尋位於磁碟的其他LSM樹元件。

4.5 LSM樹刪除、更新

4.5.1 刪除

注意,刪除也可以和插入一樣享用延遲和批處理的好處。
具體來說,當一個索引行被刪除時,如果一個key-value鍵值對沒有在C0樹中找到,那麼可以把一個刪除節點條目放到該位置,同樣會被key索引,但該索引指向一個應該被刪除的RowId條目。而真正的刪除可在稍後的滾動合併過程中掃描到真正的該索引條目時完成:其實就是將刪除節點條目合併到更大的元件時,遇到對應的真實條目是就之間被真正刪除了,就跟正反物質湮滅一樣,一遇到就嗖的一下雙雙歸西了。

同時,查詢請求必須被那些刪除節點條目過濾掉,避免結果中返回要被刪除的記錄。這個過濾很容易實現,很容易想到那些刪除節點條目肯定是在相較於真實條目較早的元件上,這樣還能使得搜尋儘量早的發現條目被刪除而不必搜尋到最後的元件才返回。

還有另一種高效索引修改的操作。稱為謂詞刪除的過程提供了一種通過簡單地斷言謂詞來執行批量刪除的方法,例如,刪除時間戳超過20天的所有索引值的謂詞。當存在於最老(也是最大)的LSM元件中的受影響條目,在滾動合併的過程中變為記憶體駐留時,此斷言會導致它們在合併過程中被簡單地刪除

4.5.2 更新

導致索引值更改的記錄更新,這在任何型別的應用程式中都是不常見的。但如果我們將更新視為刪除後緊跟著插入,則可以由LSM樹以延遲方式處理此類更新。

4.5.3 長延時查詢

長延遲查詢的結果可以等待最慢的合併遊標的迴圈週期,LSM提供了響應查詢的有效手段。 在元件C0中插入查詢註釋條目,該查詢會在遷移到後續元件時真正執行。 一旦該查詢註釋條目迴圈合併到達了LSM樹的最大元件的適當區域,就完成了長延遲查詢的過程,最終返回累積得到的RowID列表。

0x05 LSM併發

5.1 LSM樹多元件原理回顧

回顧下前面的內容,考慮K+1個元件的LSM樹,擁有C0, C1, C2 … Ck,這樣一個遞增的索引樹結構。其中C0是駐留在記憶體的,而且他元件都在磁碟。這種情況下,每當Ci-1 條目數量達到閾值時,每個(Ci-1,Ci)之間的非同步滾動合併過程會從較小的元件中移動條目到較大的元件。每個駐留磁碟元件都是由磁碟頁大小的節點按B樹型別結構組成,此外根節點下的各層的節點都按照key的順序排列並打包放置到多頁塊中。LSM樹上層的目錄資訊可以指引單個頁節點訪問,還能指明哪些節點位於該多頁塊上,這樣的好處是使得可以一次性執行對這樣的塊的讀取或寫入。

等值匹配時,一個基於此盤的Ci可被單獨駐留在單頁記憶體快取中,也可被包含在多頁塊的快取中。作為大範圍搜尋或是滾動合併的遊標穿過塊高頻訪問的結果,一個多頁快取會被快取到記憶體。

5.2 LSM併發三大問題

無論如何,Ci元件的所有非鎖定節點都可以隨時進行訪問目錄查詢,並且磁碟訪問將執行旁路以查詢記憶體中的任何節點,即使該節點是多頁塊一部分,參與滾動合併。總的來說,LSM樹的併發訪問必須解決以下三種物理衝突:

  1. 一個查詢操作不應該訪問一個基於磁碟元件的同時,另外一個程序正在滾動合併且正在修改該節點的內容。(讀寫不能併發)
  2. 當另外的程序正在更改C0某部分以執行滾動合併到C1的同時,在C0元件中查詢或插入不應訪問C0樹的相同部分。(讀和刪除合併不能併發)
  3. 用來將資料從Ci-1移動到Ci的遊標有時候需要穿越過用來將資料從Ci移動到Ci+1的遊標,因為從Ci-1的資料匯出速度總是至少與Ci資料匯出資料相當,這就意味著Ci-1的遊標運轉速度更快。
    無論採用何種併發方法,都必須允許上述情況發生,也就是說匯出資料到Ci的程序不會因Ci從資料匯出的程序而阻塞。

5.3 基於磁碟元件合併時的併發

LSM樹中用於併發控制訪問基於磁碟的元件而導致衝突,所以加鎖的單位是樹的節點:

  • 正在因滾動合併被修改的節點會被加上寫鎖
  • 正在因搜尋而讀取的節點會被加上讀鎖
  • 為了防止死鎖,設計了目錄鎖相關方法

而C0樹採用的鎖實現方式具體依據是採用的資料結構。

  • 例如,在 2-3樹 的情況下,我們可以用寫鎖鎖住2-3樹的目錄節點一個子樹,該節點包含要合併到C1節點時受影響範圍內的所有條目;
  • 同時,查詢操作會用讀鎖鎖定那些處於搜尋路徑上的2-3樹的所有節點,這是一個排他鎖。

鎖的釋放:

  • 讀鎖
    一旦葉節點上的條目被掃描完了,就會釋放
  • 寫鎖
    滾動遊標使用的寫鎖會在合併到更大的元件後背釋放

為了提高併發,前面章節提到過的C1樹的empty blockfilling block都會包含整數個C1樹中的頁大小的節點,並駐留在記憶體。在合併重組節點時,這些節點會被加上寫鎖,以阻止對這些記錄的其他型別併發訪問。

5.4 C0到C1之時的併發

前面討論的都是基於磁碟的元件間merger時的併發情況,現在說說C0到C1的合併時的併發情況。與其他合併步驟相同,CPU應該專注於合併任務,所以其他訪問會被排他的寫鎖拒絕,當然這個時間會盡可能短。那些會被合併的C0條目應該被提前計算、提前加寫鎖。除此之外,CPU時間還會由於C0元件以批量的形式刪除條目節省時間,而不是每次單獨刪除而嘗試再平衡;C0樹可以在整個合併步驟完成後被完全的平衡。

0x06 LSM恢復

注意,本章轉自
日誌結構的合併樹 The Log-Structured Merge-Tree
作者:眺望海接天

6.1 檢查點

在新條目插入到C0後,當C0與C1進行滾動合併時,某些條目將從C0轉移到更大的元件中。由於滾動合併發生在記憶體快取的多頁塊中,所以只有當條目真正寫入硬碟時,滾動合併的成果才會真正生效。然而滾動合併時可能就會發生系統故障,進而使得記憶體資料丟失。為了能有效地進行系統恢復,在LSM樹的日常使用中,需要記錄一些用以恢復資料的日誌。然而與以往資料庫中的日誌不同的是,日誌中只需要要記錄資料插入的事務。簡單地說,這些日誌只包含了被插入資料的行的號碼及插入的域和值。

LSM樹在記日誌時設定檢查點(checkpoint)以恢復某一時刻的LSM-tree。當需要在時刻T0設定檢查點時:

  1. 完成所有元件的當前正在進行的合併,這樣結點上的鎖就會被釋放;
  2. 將所有新條目的插入操作以及滾動合併推遲至檢查點設定完成之後;
  3. 將C0寫入硬碟中的一個已知的位置;此後對C0的插入操作可以開始,但是合併操作還要繼續等待;
  4. 將硬碟中的所有部件(C1~CK)在記憶體中快取的結點寫入硬碟;
  5. 向日志中寫入一條特殊的檢查點日誌。
    檢查點日誌的內容包括:
  6. T0時刻最後一個插入的已索引的行的日誌序列號(Log Sequence Number,LSN0);
  7. 硬碟中的所有部件的根在硬碟中的地址;
  8. 各個部件的合併遊標;
  9. 新多頁塊動態分配的當前資訊。在以後的恢復中,硬碟儲存的動態分配演算法將使用此資訊判別哪些多頁塊是可用的。
    Checkpoint

一旦檢查點的資訊設定完畢,就可以開始執行被推遲的新條目的插入操作了。由於後續合併操作中向硬碟寫入多頁塊時,會將資訊寫入硬碟中的新位置,所以檢查點的資訊不會被消除。只有當後續檢查點使得過期的多頁塊作廢時,檢查點的資訊才會被廢棄。

6.2 恢復

當系統崩潰後重啟進行恢復時,需要進行如下操作:

  1. 在日誌中定位一個檢查點;
  2. 將之前寫入硬碟的C0和其它部件在記憶體中快取的多頁塊載入到記憶體中;
  3. 將日誌中在LSN0之後的部分讀入記憶體,執行其中索引條目的插入操作;
  4. 讀取檢查點日誌中硬碟部件(C1~CK)的根的位置和合並遊標,啟動滾動合併,覆蓋檢查點之後的多頁塊;
  5. 當檢查點之後的所有新索引條目都已插入至LSM-tree且被索引後,恢復即完成。
    這一恢復措施的唯一的一個缺點就是恢復的時間可能會比較長,但通常這並不嚴重。因為記憶體中的資料可以很快地寫入硬碟。當兩個相鄰的部件進行滾動合併時,新產生的結點將會寫入到硬碟中的新位置。這樣在將合併產生的結點寫入硬碟時,上層結點中指向該結點的指標需要更新為結點的新位置。當正在進行滾動合併,卻臨時需要設定檢查點時,載入進記憶體的多頁塊和目錄結點都會寫入到硬碟中新的位置。這樣,在高層的目錄結點中指向這些結點的指標同樣需要立即更新為硬碟中的新地址。在恢復的過程中需要注意的是目錄結點的更新。

高層結點引用下層結點的新位置

更進一步,當使用檢查點進行恢復時,滾動合併所需的所有的多頁塊都會從硬碟重新讀回記憶體,由於所有的多頁塊的新位置較之設定檢查點時的舊位置都發生了改變,這樣所有目錄結點的指標都需要更新。這聽起來似乎是一大筆效能開銷,但這些多頁塊其實都已載入到記憶體裡了,所以沒有I/O開銷。若要使得恢復的時間不超過幾分鐘,那麼可以每隔幾分鐘的I/O操作就設定一次檢查點。

0x07 結論

  • B樹,因為它最常用的目錄節點是可快取在記憶體裡的,所以實際上是一種混合資料結構:它結合了低成本磁碟和高成本記憶體,前者用來存放大多數的資料,後者為最熱門的資料提供訪問。
  • 而LSM樹將此層次結構擴充套件到多個層級,並在執行多頁磁碟資料讀取時結合了merge IO的優點。

下圖展示了對於通過B樹以及LSM樹(僅包含記憶體中的C0和和磁碟上的C1樹)的兩種資料訪問模式的資料熱度,縱軸是訪問開銷/MB;橫軸是插入速率/MB
LSM樹-B樹對比
從上圖可以得到以下結論:

  • 最低的訪問速率時,Cold Data的磁碟訪問開銷並太高
  • Warm Data階段,B樹結構的資料訪問成本開銷急劇上升,此時磁碟臂會成為磁碟訪問的主要限制因素;而LSM樹結構的資料訪問成本上升很緩慢
  • 到了Hot Data階段,B樹結構的資料都應該快取到記憶體中了,此時稱之為沸點。使用記憶體快取對B樹來說效果顯著,隨著訪問速率進入Hot Data區域而開銷圖形卻變平緩,甚至更頻繁的訪問也不會導致更高的成本上升;而我們可以看出LSM樹的作用是降低訪問成本,對於任何實際訪問速率的諸如插入和刪除之類的可合併操作,特別是針對Cold Data

此外,很多需要快取B樹的情況,如上圖中的Hot Data階段,其實可以用大部分駐留在磁碟的LSM樹來代替。在這些場景中,由於LSM樹的批處理效應,資料在邏輯訪問速率方面是Hot的,但在磁碟物理訪問的速率方面僅是Warm的。 對於具有大量可合併操作(寫入、刪除)的應用程式而言,這是一個非常重要的優勢。

綜合來看,LSM-tree的代價曲線在B-tree之下,可見LSM-tree對硬碟和記憶體的利用率都比B-tree要高。這主要是因為兩點:

  1. 滾動合併時批量寫入新插入的資料,平攤單個條目插入的開銷;
  2. C1的各層結點儲存在多頁塊中,合併時順序讀寫多頁塊,減小磁碟臂的移動。

0x08 好文推薦

網上有一些關於此論文的分析文章,在此推薦下:

0xFF 參考文件