一文帶你瞭解 LSM Compaction

做者:螞蟻金服OceanBase數據庫高級技術專家 華庭算法

當前,基於LSM架構的存儲系統很常見,對該架構來講,compaction(合併)是一個重要操做,本文帶你瞭解compaction相關知識。

10年前Google發表BigTable的論文,推進了基於LSM的系統架構的流行,用戶數據寫入先寫WAL,再寫Memtable,知足必定條件後凍結Memtable,執行轉儲操做造成一個數據文件SSTable。隨着數據寫入不斷增多,轉儲次數也會不斷增多,進而轉儲SSTable也會愈來愈多。然而,太多SSTable會致使數據查詢IO次數增多,所以後臺嘗試着不斷對這些SSTable進行合併,這個合併過程稱爲Compaction。Compaction分爲兩類:Minor Compaction和Major Compaction。數據庫

Minor Compaction是指選取一個或多個小的、相鄰的轉儲SSTable與0個或多個Frozen Memtable,將它們合併成一個更大的SSTable。一次Minor Compaction的結果是更少而且更大的SSTable。緩存

Major Compaction是指將全部的轉儲SSTable和一個或多個Frozen Memtable合併成一個SSTable,這個過程會清理被刪除的數據。通常狀況下,Major Compaction時間會持續比較長,整個過程會消耗大量系統資源,對上層業務有比較大的影響。                          架構

compaction放大因子

一般Compaction涉及到三個放大因子,Compaction須要在三者之間作取捨。
性能

寫放大

Write Amplification : 寫放大,假設每秒寫入10MB的數據,但觀察到硬盤的寫入是30MB/s,那麼寫放大就是3。寫分爲當即寫和延遲寫,好比redo log是當即寫,傳統基於B-Tree數據庫刷髒頁和LSM Compaction是延遲寫。redo log使用direct IO寫時至少以512字節對齊,假如log記錄爲100字節,磁盤須要寫入512字節,寫放大爲5。測試

讀放大

Read Amplification : 讀放大,對應於一個簡單query須要讀取硬盤的次數。好比一個簡單query讀取了5個頁面,發生了5次IO,那麼讀放大就是 5。假如B-Tree的非葉子節點都緩存在內存中,point read-amp 爲1,一次磁盤讀取就能夠獲取到Leaf Block;short range read-amp 爲1~2,1~2次磁盤讀取能夠獲取到所需的Leaf Block。優化

空間放大

Space Amplification : 空間放大,假設我須要存儲10MB數據,但實際硬盤佔用了30MB,那麼空間放大就是3。有比較多的因素會影響空間放大,好比在Compaction過程當中須要臨時存儲空間,空間碎片,Block中有效數據的比例小,舊版本數據未及時刪除等等。設計

最近幾年不少論文對LSM寫放大有比較多的研究,而對於寫放大自己而言,是一個很古老的問題,在計算機體系中,若是相鄰兩層的處理單元不一致或者應用對一致性等有特殊的需求,就極可能出現寫放大問題。好比CPU Cache和內存cell,文件系統Block和磁盤扇區,數據庫Block和文件系統Block,數據庫redo/undo,文件系統journal等。下圖是PebblesDB論文中測試了幾款流行KV的放大係數對比:cdn

RocksDB放大係數高達42倍,LevelDB也高達27倍。寫放大意味着更多的讀寫,會形成系統性能波動,好比對SSD來講會加速壽命衰減,從成本角度說也更加耗電,採用更優的避免寫放大的算法可使用成本更低廉的SSD,寫放大還影響數據庫系統的持續寫入的帶寬,假如磁盤帶寬爲500M/s,寫放大爲10,那麼數據庫持續寫入的的最大帶寬爲50M/s,因此解決寫放大就成了一個很重要的問題。blog

Facebook在Fast 14提交的論文《Analysis of HDFS Under HBase: A Facebook Messages Case Study》所提供的一些測試結論:在Facebook Messages業務系統中,業務讀寫比爲99:1,而最終反映到磁盤中,讀寫比卻變爲了36:64。

放大問題的本質是一個系統對「隨時全局有序"的需求有多麼的強烈。所謂隨時,就是任何的寫入都不能致使系統無序;所謂全局,即系統內任意元單位之間都要保持有序。B-Tree系列是隨時全局有序的典型表明,而Fractal Tree打破了全局的約束,容許局部無序,提高了隨機寫能力;LSM系列進一步打破了隨時的約束,容許經過後臺的Compaction來整理排序。在LSM這種依靠後臺整理來保序的系統裏面,系統對序的要求越強烈,寫放大越嚴重。

要同時將寫放大,讀放大,空間放大優化到最優是很難的,好比SSD內部的碎片整理,碎片越多,空間放大和讀放大越嚴重,爲了改善空間放大和讀放大,將page中的有效數據拷貝到新的page裏(copy-out),這樣會帶來寫放大,若是page中有效數據率越低,那麼空間放大越大,copy-out的寫放大越低,反之,空間放大越小,copy-out寫放大越大。

compaction的做用與反作用

隨着數據寫入不斷增長,Minor Freeze不斷觸發,轉儲數據不斷增多,一次查詢可能須要愈來愈多的IO操做,讀取延時也在不斷變大。而執行Minor Compaction會使得轉儲文件數基本穩定,進而IO Seek次數會比較穩定,延遲就會穩定在必定範圍。然而,Minor Compaction操做重寫文件會帶來很大的帶寬壓力以及短期IO壓力。所以能夠認爲,Minor Compaction就是使用短期的IO消耗以及帶寬消耗換取後續查詢的低延遲。

爲了換取後續查詢的低延遲,除了短期的讀放大以外,Compaction對寫入也會有很大的影響。當寫請求很是多,致使不斷觸發Minor Compaction生成轉儲SSTable,屢次Minor Freeze會觸發Major Freeze,從而致使Major Compaction,但Compaction的速度遠遠跟不上數據寫入速度,Memtable內存不足時,會限制用戶數據寫入。若是Compaction消耗大量IO和帶寬,也會致使讀性能急劇降低。爲了不這種狀況,在Memtable內存緊張時候會限制寫請求的速度。

Minor Compaction釋放Memtable內存,清理沒必要要的多版本數據,同時保證轉儲SSTable數量穩定,下降讀延遲;Major Compaction清除刪除和過時的數據,有效下降存儲空間,也能夠有效下降讀取時延。Compaction會使得數據讀取延遲一直比較平穩,但付出的代價是大量的讀延遲毛刺和必定的寫阻塞。

compaction目標

Compaction的設計老是會追求一個平衡點,一方面須要保證Compaction的基本效果,另外一方面又不會帶來嚴重的IO壓力。然而,並無一種設計策略可以適用於全部應用場景或全部數據集。Compaction選擇什麼樣的策略須要根據不一樣的業務場景、不一樣數據集特徵進行肯定。設計Compaction策略須要根據業務數據特色,目標就是下降各類放大,不斷權衡以下幾點:

合理控制讀放大:避免因Minor Freeze增多致使讀取時延出現明顯增大,避免請求讀取過多SSTable;

合理控制寫放大:避免一次又一次地Compact相同的數據;

合理控制空間放大:避免讓不須要的多版本數據,已經刪除的數據和過時的數據長時間佔據存儲空間,避免在Compaction過程當中佔用過多臨時存儲空間,及時釋放已經Compact完成的無用SSTable的存儲空間;

控制Compaction使用的資源:在業務高峯期少使用資源,業務低峯期使用更多的資源;

控制Compaction平滑度:在必定的負載下,業務的響應時間和吞吐量穩定可預期;

compaction算法演進

Memtable(增量數據) + L1(基線數據)

這是一種比較理想的場景,機器的內存比較大,磁盤空間和業務數據比較小,業務天天的修改幾乎能夠所有存儲在Memtable中,採用每日Major Compaction的方式將增量數據與基線數據進行合併,以下圖所示:


每張表包含一個增量數據Memtable和一個基線數據SSTable,這種每日Major Compaction算法比較簡單,point read-amp爲1,short range read-amp爲1,空間放大爲1,寫放大爲sizeof(database) / sizeof(memtable) + 1。這種Compaction算法保證最優讀放大和空間放大,在Memtable內存比較大,磁盤空間和業務數據不大的狀況下,寫放大也能夠接受,但隨着業務數據量的增加,採用壓縮率更高的壓縮算法,以及單機存儲空間的快速增加,寫放大變得很是巨大,每日Major Compaction的速度變得愈來愈慢。

Memtable(增量數據)+L0(增量轉儲數據)+L1(基線數據)

隨着業務的發展,每日更新的數據愈來愈大,Memtable已經不能存儲成天的修改數據,當系統內存緊張時,觸發Minor Freeze,而後轉儲生成SSTable,以下圖所示:



point read-amp爲>=1次磁盤讀取和屢次bloomfilter過濾,short range read-amp爲L0+L1 SSTable數量總和次磁盤讀取,寫放大爲sizeof(database) / sizeof(每日增量數據量) + 2 (redo log,L0);最近幾年單機的內存量幾乎沒有增長,但業務基線數據總量和天天的增量數據增加巨大,因此使用每日Major Compaction算法寫放大很是大。隨着L0層SSTable個數增長,讀放大不斷增長,爲了限制L0層SSTable的個數,當轉儲達到必定次數後,發起一次Major Freeze,而後啓動Major Compaction。這種策略會致使天天須要執行屢次Major Compaction,隨着基線數據量的增加,寫放大愈來愈大,Major Compaction也愈來愈慢。

根據場景選擇Compaction策略

在不一樣的場景如何折中選擇讀放大,寫放大和空間放大呢?在系統中統一採用一種Compaction策略每每比較難兼顧各類細節需求,而針對不一樣表配置不一樣的Compaction策略能更好的適應表的讀寫負載。

遞增rowkey的insert/update/delete,不管讀寫比例多少

最優寫放大和空間放大,無讀放大,採用Memtable + L1模式,若是delete range比較多,則在Memtable中標記delete range。

write only,大量隨機rowkey insert/update/delete

優化寫放大,採用Memtable + L0 + L1模式,每次轉儲生成一個SSTable,L0的總大小與L1相同時進行Major Compaction寫放大最小。

write mostly,大量隨機rowkey insert/update/delete

優化寫放大,容忍稍大的讀放大,採用Memtable + L0 + L1模式,L0層累積屢次Major Freeze的增量SSTable數據,L0層包含多個SSTable,按照優化寫放大策略控制L0層SSTable數量和大小,使用Stripe Compaction和漸進合併策略減小Major Compaction的寫放大和臨時空間放大。

read only,或write不多

最優寫放大,讀放大和空間放大,採用Memtable + L1模式,Memtable沒有數據或只有少許數據。

read mostly,少許隨機rowkey insert/update/delete

優化讀放大,採用Memtable + L0 + L1模式,每次轉儲Frozen Memtable與前一個L0層SSTable合併成一個新的L0層SSTable,若是delete range比較多,則在Memtable和L0層SSTable中標記delete range,L0與L1進行Major Compaction的寫放大比較小。

read mostly,大量隨機rowkey insert/update/delete

優化寫放大和讀放大,採用Memtable + L0 + L1模式,L0層累積屢次Major Freeze的增量SSTable數據,L0層包含多個SSTable,根據用戶的訪問熱點決定哪些range內的L0層SSTable合併,若是delete range比較多,則在Memtable和L0層SSTable中標記delete range,將L0和L1分紅多個sub-range條帶,每一個sub-range積累了足夠增量數據後才進行Major Compaction,相似漸進合併的方式,每次Major Freeze都合併L0和L1的部分range數據。若是delete比較多,空間放大不優,不能即便釋放已經刪除數據的存儲空間。

相關文章
相關標籤/搜索