日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

深入理解LSM-Tree

發布時間:2024/2/28 编程问答 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入理解LSM-Tree 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

深入理解LSM-Tree

    • 基礎概念
    • compaction策略
      • Size-tired compaction strategy(STCS)/Tiered
      • leveled compaction
        • Leveled-N
      • Hybrid
      • Time-Window
      • 比較
    • 工業實現
      • leveldb
      • RocksDB
        • Write Stalls
      • scyllaDB/cassandra
      • hbase
      • TiKV/Titan
    • 學術研究
      • Dostoevsky
    • 參考鏈接


lsm-tree的背景、定義和適用場景本文不再詳述。本文意在論述LSM的存儲引擎、工業取舍以及發展現狀。

基礎概念

  • 讀放大(read amplification):一次讀取操作需要訪問磁盤的次數,主要由compaction策略引入??梢砸隿ache和bloom filter優化。
  • 寫放大(write amplification):一次寫操作帶來的數據落盤的次數。在LSM-Tree中可由某個key數據在磁盤上存儲的數量這個指標體現,主要是由compaction策略引入的。
  • 空間放大(space amplification):實際空間占用/理論數據量,LSM-Tree的架構導致空間放大必然存在
  • 臨時空間:compaction任務需要臨時的空間來完成多個sstable的合并。
  • run:借用wiki中的解釋:
    • The on-disk data is organized into sorted runs of data. Each run contains data sorted by the index key. A run can be represented on disk as a single file, or alternatively as a collection of files with non-overlapping key ranges. To perform a query on a particular key to get its associated value, one must search in the Level 0 tree and each run.

    • 可見,每一個run都是有序的數據塊。
  • compaction策略

    LSM-Tree存儲引擎的工作流程如下:

  • 當寫入時,將其天際到內存的平衡樹數據結構中(如紅黑樹、AVL樹或SkipList),這個內存樹有時候被稱為MemTable(leveldb)。
  • 當內存表大于某個閾值(通常以MB為單位),將其作為SSTable文件寫入磁盤,由于樹已經維護了按鍵排序的key-value對,寫磁盤的效率可以比較高效。新的SSTable文件稱為數據庫的最新部分,當SSTable寫磁盤的同時,寫入可以繼續添加到一個新的內存表中
  • 不同的實現使用了不同的壓縮合并策略,用以優化write-intensive或read-intensive場景。
  • LevelDB和RocksDB使用leveled compaction,HBase采用tiered compaction,Cassandra則同時支持這兩種壓縮。
  • 為了處理讀請求,首先嘗試在內存表中查找key,然后按照LSM-Tree的層級依次向下查找,知道找到或未找到目標。
  • 后臺進程周期性的執行段合并與壓縮過程,合并多個SSTable,丟棄已經stale的值。
  • 從上面的存儲流程可以看出,LSM-Tree的性能主要取決于Compaction策略,它主要分為兩類,tiered compactionleveled compaction

    • tiered流派從Bigtable->HBase->Cassandra一脈相承,后面又有MyRocks、InfluxDB、Kudu等等
    • Leveled流派工程實現主要有LevelDB->RocksDB

    Size-tired compaction strategy(STCS)/Tiered

    tiered適合write-intensive workload,有較低的寫放大,缺點是讀放大和空間放大較高。

    tiered compaction的策略是:memtable達到閾值之后刷入下一層(落盤)作為一個run,每層的run達到一定數量之后,將當前層所以的run進行compaction并刷入下一層,循環往復。這種策略給人直觀的感受是,越下層的run越大,當然實際的策越要比描述的復雜,因為run與run之間重疊的部分是不確定的,有可能完全重疊,也有可能完全不重疊。

    • 由于所有的上層level的數據可以直接追加寫入下層,所以寫放大比較低
    • 由于每層都有多個run,且每個run中的數據可以重疊,所以點讀操作需要由上到下遍歷每一個run,讀放大較嚴重。更不要提range查詢肯定要合并每一層的每一個run的查詢結果,讀放大更嚴重。
    • 由于每層有多個run,每個run都可能含有重疊數據,所以空間放大較為嚴重??臻g放大可以說是STCS最嚴重的問題了。Scylla的文章通過實驗論證了這個問題
    • 每層的多個run需要先合并,才能寫入下層,因此有可能導致臨時空間較大。耗時也較長
    • 這里討論一個特例time-series data。key是時間,幾乎是恒定遞增的,因此越是下層,run越是不重疊,寫入和查詢的策略都可以做對應的優化。

    leveled compaction

    leveled compaction和上面的STCS相比,降低了空間放大和讀放大,比較適合read-intensive workload,當然這個也只是相對而言,如果真的是讀很多,不如用B+ Tree。

    leveled compaction每層只維護一個run,按照key排序可以分為多個partition(SSTable file)。每層容量達到一定限制后,選擇某個sstable與上層merge。

    • 由于每層只有一個run,所以降低了讀放大和空間放大。但是點查詢仍然有可能會遍歷所有的run、范圍查詢必然會遍歷所以的run。
    • 由于leveled compaction上層與下層merge的過程有可能涉及到上下層所有的數據,可能造成上層run全量重寫,導致寫入放大,但是由于每個run可以分為多個partition(sstable),因此可以節約部分臨時空間。

    Leveled-N

    不同于leveled,Leveled-N允許每層多個Sorted run。Dostoevsky paper引入了一種Fluid LSM:允許最高層只有一個run,而其它層可以有多個run。

    Hybrid

    這里討論scylladb實現的Hybrid模式。主要體現在這篇文章,其希望推出一種模式,可以吸納tiered和leveled兩者的優點。scylladb引入Hybrid主要為了優化tiered糟糕的空間放大。我推測主要有以下幾點優化:

  • 總體布局和tiered類似,只不過每層的run的數量可以根據負載動態調節,下層的run可以直接merge到上層的run里面。
  • 運行時可以感知到當前磁盤剩余空間和run的key分布,如果剩余空間不多或這個每個run重疊太多(說明是overwrite場景),則compaction略逐步由tiered向leveled轉移。
  • 總的來說我覺得這個優化是將rocksDB繁雜的優化參數調整為代碼中的一些策略,以優化特定的workload
  • Time-Window

    這里主要講scylladb/Cassandra針對時序數據引入的Time-Window compaction,時序數據有以下特點:

  • key是單調遞增的(timeline),
  • 寫入速率基本恒定,
  • 查詢方式以range-query為主,如查詢某年、月、日的數據
  • 可以通過設置TTL的方式刪除超過一定時間的數據。
  • 這種數據狀況下,通過將不同的時間分配在不同的Time-Window中,將SSTable分配成了一個個time bucket,實現形式上采用tiered compaction,不同的time bucket不會合并(優化讀操作)。由于overlap并不多,所以compaction壓力不大,空間放大也不大。由于數據分布較好,查詢也較方便。

    比較

    scylladb的文章總結了以下表格:

    workloadSize-TieredLeveledHybridTime-Window
    Write-only2x peak space2x writesBest-
    Overwrite(指同一個key多次update)Huge peak spacewrite amplificationhigh peak space bug not like size-tiered-
    Read-mostly, few updatesread amplificationBestread amplification-
    Read-mostly, but a lot of updatesread and space amplificationwrite amplification may overwhelmread amplification-
    Time serieswrite,read,and space amplificationwrite and space amplificationwrite and read amplificationbest

    工業實現

    leveldb

    顧名思義,levelDB使用leveled compaction,其CRUD流程如下:

  • 寫流程:
  • 找到合適的memtable(skiplist)并寫入數據,如果memtable寫完并且immutableTable還未完成持久化,或者L0文件太多,則等待。如果memtable滿了,則換一個memtable,并觸發compaction。由此可見,l0是tiered,對于每個run,key的范圍有重疊。其它層是leveled
  • 寫日志,下刷日志
  • 寫memtable
  • 讀流程:
  • 首先查找memtable,再查找immutable memtable
  • 如果沒有,查找下面所有持久化的levelVersion::Get,逐層向下搜索。搜索方法的策略是并不是遍歷每一個sstable,而是先看需要查找的key是否落在sstable的范圍內,如果落在,對sstable搜索。
  • 對于讀取mem中的數據(skiplist),正向遍歷時間復雜度是O(1),反向遍歷時間復雜度是O(log(N))
  • 對于讀取sstable中的數據,正向遍歷有指針指向下一個數據位置,反向遍歷每次Prev()都要重新定位
  • 刪除流程:
  • 后臺線程也會按需做compaction。通過MaybeScheduleCompaction()函數判斷。
  • levelDB代碼清晰,代碼量少,閱讀方便,不過缺少大規模工程應用場景。

    RocksDB

    LSM-Tre工業級實現,和levelDB相比,參數更多,優化更多,使用更靈活,Features Not in LevelDB這篇文章介紹了RocksDB相對于levelDB所做的優化,我選擇一些優點列舉如下:

  • 實現了tiered(Universal Compaction),tiered+leveled(l0 tiered,高層leveled),和FIFO compaction(一條數據寫入后,超過 TTL 指定的時間戳,就過期淘汰,對用戶不可見。)
  • 前綴遍歷,針對相同前綴(prefix)的場景做了優化Options.prefix_extractor
  • checksum數據校驗
  • 支持多線程compaction
  • 支持全量和備份
  • 支持read-only模式以優化讀速度
  • memtable優化:
  • 支持多種數據結構:skiplist為默認,vector模式以優化Bacth-insert,hashtable模式以優化讀操作。
  • 支持多memtable并發插入(Memtable Pipelining)
  • memtable持久化的時候會做合并,GC掉某些舊數據
  • Column Families,可以設置某個kv歸并為一個column family列族,如{cf1, key1, value1},列族之間可以相互隔離(不共享memtable和sstable)
  • Write Stalls

    RocksDB會在某種情況下限制前臺寫請求的速度,稱為Write Stalls。產生的原因不外乎因為某種原因,compaction的速率趕不上前臺write的速率了。這種現象如果持續下去,會產生以下結果:

  • 空間放大增大,寫入的數據來不及壓縮,最終耗盡磁盤空間
  • 讀放大增大,越是來不及compact,讀放大就越大
  • 這種情況下需要將前臺寫請求降速,直到compaction執行到某種可以繼續高效處理前臺讀寫請求的程度。

    一般情況下,Write Stall產生的原因有以下幾種可能:

  • memtable,前臺寫入太快,memtable過多,而且都沒有flush進l0
  • l0 SSTable過多,導致讀放大、merge也慢
  • pending compaction bytes過多。磁盤 I/O 能力在業務高峰跟不上寫入
  • scyllaDB/cassandra

    scyllaDB/cassandra默認采用tiered,可以配置為levled、Hybrid或Time-Window。只有Hybrid是ScyllaDB獨有。實現細節如上所述

    hbase

    HBase是一個分布式,版本化,面向列的開源數據庫(面向列族Column Family,在)、分布式持久化KV數據庫。HDFS(僅支持追加寫)為Hbase提供可靠的底層數據存儲服務,MapReduce為Hbase提供高性能的計算能力,Zookeeper為Hbase提供穩定服務和Failover機制,因此我們說Hbase是一個通過大量廉價的機器解決海量數據的高速存儲和讀取的分布式數據庫解決方案。Hbase適合存儲PB級別的海量數據,雖然當個請求是時延不低,但是可以通過并行請求增大吞吐,并且單個IO的時延下降并不多。

    架構和bigtable比較類似,通過key-range,將數據水平切分到多臺服務器上,數據持久化在HDFS中。這點和現代的應用如tidb略有不同,其是將數據切分之后通過一致性協議存儲在多個RSM上,每個RSM的數據引擎為LSM-Tree

    Hbase 技術細節筆記(上)

    hbase在實現中,是把整個內存在一定閾值后,flush到disk中,形成一個file,這個file的存儲也就是一個小的B+樹,因為hbase一般是部署在hdfs上,hdfs不支持對文件的update操作,所以hbase這么整體內存flush,而不是和磁盤中的小樹merge update。內存flush到磁盤上的小樹,定期也會合并成一個大樹。整體上hbase就是用了lsm tree的思路。

    因為小樹先寫到內存中,為了防止內存數據丟失,寫內存的同時需要暫時持久化到磁盤,對應了HBase的HLog(WAL)和MemStore

    MemStore上的樹達到一定大小之后,需要flush到HRegion磁盤中(一般是Hadoop DataNode),這樣MemStore就變成了DataNode上的磁盤文件StoreFile,定期HRegionServer對DataNode的數據做merge操作,徹底刪除無效空間,多棵小樹在這個時機合并成大樹,來增強讀性能。

    TiKV/Titan

    TiKV使用RocksDB作為存儲引擎,并且實現了Titan作為RocksDB 的高性能單機 key-value 存儲引擎插件。以支持大value(Blob),其核心特性在于支持將 value 從 LSM-tree 中分離出來單獨存儲,以降低寫放大。

    其主要設計靈感來源于 USENIX FAST 2016 上發表的一篇論文 WiscKey。WiscKey 提出了一種高度基于 SSD 優化的設計,利用 SSD 高效的隨機讀寫性能,通過將 value 分離出 LSM-tree 的方法來達到降低寫放大的目的。

    Titan 適合在以下場景中使用:

  • 前臺寫入量較大,RocksDB 大量觸發 compaction 消耗大量 I/O 帶寬或者 CPU 資源,造成 TiKV 前臺讀寫性能較差。
  • 前臺寫入量較大,由于 I/O 帶寬瓶頸或 CPU 瓶頸的限制,RocksDB compaction 進度落后較多頻繁造成 write stall。
  • 前臺寫入量較大,RocksDB 大量觸發 compaction 造成 I/O 寫入量較大,影響 SSD 盤的壽命。
  • 學術研究

    Dostoevsky

    這篇論文詳細地分析了各種操作在tired和leveled不同策略下的i/o復雜度,使用了level num、相鄰level size比、entry數量、buffer size等一系列相關變量推導出不同操作具體的I/O代價公式和空間放大,對于point read還考慮了bloom filter帶來的影響,range query分了short和long兩種來分析。并且提出了優化策略lazying leveling,是tiering和leveling的結合體,最大一層使用leveling其它層使用tiering,lazying適合包含update、point lookup和long range lookup的混合負載,tiering適合大多為update的負載,leveling適合大多為lookup的負載。通過控制merge頻率在tiering、leveling和lazying leveling幾種不同策略下轉換以適應不同的workload,稱作fluid LSM((類似rocksdb的leveled-n)),并提出Dostoevsky,在執行期間動態計算最優配置以到達最大吞吐。

    從作者的分析中可以看出compaction這個機制的復雜程度,要使用一套通用機制在不同場景下消耗最少的資源帶來最好的性能基本是不可能的,實際工業界實現中需要考慮更多的因素(cache、delete、任務拆分粒度、復用技術等),因此大部分系統使用多種策略多個參數用以適配不同場景。

    參考鏈接

  • Cassandra Compaction
  • LevelDB 之 Compaction
  • 深入探討LSM Compaction機制
  • LSM Tree的Leveling 和 Tiering Compaction
  • Scylla’s Compaction Strategies Series: Space Amplification in tiered CompactionSTCS圖出處
  • Size Tiered Compaction Strategy In Apache Cassandra
  • rocksdb Leveled Compaction 圖文并茂
  • RocksDB Overview
  • RocksDB Performance Benchmarks
  • Direct IO什么場景里可以使用directIO
  • RocksDB調優指南翻譯自官方wiki
  • RocksDB中文網
  • RocksDB Tuning Guide
  • Compaction rocksdb講tirered和leveled
  • Name that compaction algorithmTiered/Leveled比較,這哥們專門做lsmtree的。
  • How to Ruin Your Performance by Choosing the Wrong Compaction Strategyscylladb的這篇文章寫得很好
  • Scylla’s Compaction Strategies Series: Write Amplification in Leveled Compaction
  • Scylla’s Compaction Strategies Series: Space Amplification in Size-Tiered Compaction
  • Titan 的設計與實現
  • SIGMOD’18|Dostoevsky
  • 總結

    以上是生活随笔為你收集整理的深入理解LSM-Tree的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。