<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一文科普 RocksDB 工作原理

          共 9691字,需瀏覽 20分鐘

           ·

          2023-05-29 21:40

          本篇文章來(lái)自我的小報(bào)童專欄,初步規(guī)劃有以下幾個(gè)系列:

          • 圖數(shù)據(jù)庫(kù)101系列
          • 每天學(xué)點(diǎn)數(shù)據(jù)庫(kù)系列
          • 系統(tǒng)好文推薦系列
          • 讀書筆記系列
          • 數(shù)據(jù)密集型論文導(dǎo)讀系列
          • 源碼閱讀系列

          會(huì)保證每周不低于兩篇更新,訂閱方式見??這里,歡迎喜歡我文章的朋友們的訂閱支持,激勵(lì)我產(chǎn)出更多優(yōu)質(zhì)文章。

          RocksDB 是很多分布式數(shù)據(jù)庫(kù)的底層存儲(chǔ),如 TiKV、CRDB、NebulaGraph 等等。在 DataDog 工作的 Artem Krylysov 寫了一篇文章(原文鏈接:https://artem.krylysov.com/blog/2023/04/19/how-rocksdb-works/)來(lái)對(duì) RocksDB 做了一個(gè)科普,通俗易懂,在這里翻譯下分享給大家。

          導(dǎo)語(yǔ)

          近幾年,RocksDB 的采用率急速上升,儼然成為內(nèi)嵌型鍵值存儲(chǔ)(以下簡(jiǎn)稱 kv 存儲(chǔ))的不二之選。

          目前,RocksDB 在 Meta、Microsoft、Netflix 和 Uber 等公司的生產(chǎn)環(huán)境上運(yùn)行。在 Meta,RocksDB 作為 MySQL 部署的存儲(chǔ)引擎,為分布式圖數(shù)據(jù)庫(kù)(TAO)提供支持存儲(chǔ)服務(wù)。

          大型科技公司并非 RocksDB 的僅有用戶,像是 CockroachDB、Yugabyte、PingCAP 和 Rockset 等多個(gè)初創(chuàng)企業(yè)都構(gòu)建在 RocksDB 基礎(chǔ)之上。

          我在 Datadog 工作了 4 年時(shí)間,在生產(chǎn)環(huán)境中構(gòu)建和運(yùn)行了一系列基于 RocksDB 的服務(wù)。本文將就 RocksDB 的工作原理進(jìn)行概要式講解。

          RocksDB 是什么

          RocksDB 是一種可持久化的、內(nèi)嵌型 kv 存儲(chǔ)。它是為了存儲(chǔ)大量的 key 及其對(duì)應(yīng) value 設(shè)計(jì)出來(lái)的數(shù)據(jù)庫(kù)。可以基于這種簡(jiǎn)單 kv 數(shù)據(jù)模型來(lái)構(gòu)建倒排索引、文檔數(shù)據(jù)庫(kù)、SQL 數(shù)據(jù)庫(kù)、緩存系統(tǒng)和消息代理等復(fù)雜系統(tǒng)。

          RocksDB 是 2012 年從 Google 的 LevelDB fork 出來(lái)的分支,并針對(duì)跑在 SSD 上的服務(wù)器進(jìn)行了優(yōu)化。目前,RocksDB 由 Meta 開發(fā)和維護(hù)。

          RocksDB 使用 C++ 編寫而成,因此除了支持 C 和 C++ 之外,還能通過(guò) С binding 的形式嵌入到使用其他語(yǔ)言編寫的應(yīng)用中,例如 Rust、Go 或 Java。

          如果你之前用過(guò) SQLite,你肯定知道什么是內(nèi)嵌式數(shù)據(jù)庫(kù)。在數(shù)據(jù)庫(kù)領(lǐng)域,特別是在 RocksDB 的上下文中,“內(nèi)嵌”意味著:

          • 該數(shù)據(jù)庫(kù)沒有獨(dú)立進(jìn)程,而是被集成進(jìn)應(yīng)用中,和應(yīng)用共享內(nèi)存等資源,從而避免了跨進(jìn)程通信的開銷。
          • 它沒有內(nèi)置服務(wù)器,無(wú)法通過(guò)網(wǎng)絡(luò)進(jìn)行遠(yuǎn)程訪問(wèn)。
          • 它不是分布式的,這意味著它不提供容錯(cuò)性、冗余或分片(sharding)機(jī)制。

          如有必要,需依賴于應(yīng)用層來(lái)實(shí)現(xiàn)上述功能。

          RocksDB 以 kv 對(duì)集合的形式存儲(chǔ)數(shù)據(jù), key 和 value 是任意長(zhǎng)度的字節(jié)數(shù)組(byte array),因此都是沒有類型的。RocksDB 提供了很少的幾個(gè)用于修改 kv 集合的函數(shù)底層接口:

          • put(key, value):插入新的鍵值對(duì)或更新已有鍵值對(duì)
          • merge(key,?value):將新值與給定鍵的原值進(jìn)行合并
          • delete(key):從集合中刪除鍵值對(duì)

          通過(guò)點(diǎn)查來(lái)獲取 key 所關(guān)聯(lián)的 value:

          • get(key)

          通過(guò)迭代器可以進(jìn)行范圍掃描——找到特定的 key,并按順序訪問(wèn)該 key 后續(xù)的鍵值對(duì):

          • iterator.seek(key_prefix);?iterator.value();?iterator.next()

          Log-structured merge-tree

          RocksDB 的核心數(shù)據(jù)結(jié)構(gòu)被稱為日志結(jié)構(gòu)合并樹?(LSM-Tree)。它是一種樹形的數(shù)據(jù)結(jié)構(gòu),由多個(gè)層級(jí)組成,每層的數(shù)據(jù)按 key 有序。LSM-Tree 主要設(shè)計(jì)用來(lái)應(yīng)對(duì)寫入密集型工作負(fù)載,并于 1996 年在同名論文 The Log-Structured Merge-Tree (LSM-Tree)?被大家所知。

          LSM-Tree 的最高層保存在內(nèi)存中,包含最近寫入的數(shù)據(jù)。其他較低層級(jí)的數(shù)據(jù)存儲(chǔ)在磁盤上,層數(shù)編號(hào)從 0 到 N 。第 0 層 L0 存儲(chǔ)從內(nèi)存移動(dòng)到磁盤上的數(shù)據(jù),第 1 層及以下層級(jí)則存儲(chǔ)更老的數(shù)據(jù)。通常某層的下個(gè)層級(jí)在數(shù)據(jù)量上會(huì)比該層大一個(gè)數(shù)量級(jí),當(dāng)某層數(shù)據(jù)量變得過(guò)大時(shí),會(huì)合并到下一層。

          aa672cacab7e3236f61e19e84bb924fe.webp

          注:雖然本文主要討論 RocksDB,但涉及 LSM-Tree 的概念適用于大多數(shù)底層采用此技術(shù)實(shí)現(xiàn)的數(shù)據(jù)庫(kù)(例如 Bigtable、HBase、Cassandra、ScyllaDB、LevelDB 和 MongoDB WiredTiger)。

          為了更好地理解 LSM-Tree 的工作原理,下面我們將著重剖析它的寫 / 讀路徑。

          寫路徑

          MemTable

          LSM-Tree 的頂層被稱為 MemTable。MemTable 是一個(gè)內(nèi)存緩沖區(qū),在鍵值對(duì)寫入磁盤之前,Memtable 會(huì)緩存住這些鍵值對(duì)。所有插入和更新操作都會(huì)過(guò) MemTable。當(dāng)然也包括刪除操作:不過(guò),在 RocksDB 中,并不會(huì)直接原地修改鍵值對(duì),而是通過(guò)插入墓碑記錄(tombstone )來(lái)進(jìn)行標(biāo)記刪除。

          MemTable 具有可配置的字節(jié)數(shù)限制。當(dāng)一個(gè) MemTable 變滿時(shí),就會(huì)切到一個(gè)新的 MemTable,同時(shí)原 MemTable 變?yōu)椴豢尚薷臓顟B(tài)。

          注:MemTable 的默認(rèn)大小為 64 MB。

          現(xiàn)在,我們往數(shù)據(jù)庫(kù)寫入點(diǎn) key 看看:

                db.put("chipmunk",?"1")
          db.put("cat",?"2")
          db.put("raccoon",?"3")
          db.put("dog",?"4")

          295a8122d3babd6ea09c7dd10a259a91.webp

          MemTable:內(nèi)存中的一個(gè)有序查找表

          如上圖所示,MemTable 中的鍵值對(duì)是按 key 有序排列的。盡管 chipmunk 是最先插入的,但由于 MemTable 是按 key 有序的,因此 chipmunk 排在 cat 之后。這種排序?qū)τ诜秶鷴呙枋潜仨毜?,此外,稍后我?huì)詳細(xì)介紹,它也會(huì)讓某些操作更加高效。

          預(yù)寫日志

          無(wú)論是在進(jìn)程意外崩潰退出還是計(jì)劃內(nèi)重啟時(shí),其內(nèi)存中的數(shù)據(jù)都會(huì)丟失。為了防止數(shù)據(jù)丟失,保證數(shù)據(jù)的持久化,除了 MemTable 之外,RocksDB 會(huì)將所有更新寫入到磁盤上的預(yù)寫日志(WAL,Write-ahead log)中。這樣,在重啟后,數(shù)據(jù)庫(kù)可以回放日志,進(jìn)而恢復(fù) MemTable 的原始狀態(tài)。

          WAL 是一個(gè)只允許追加的文件,包含一組更改記錄序列。每個(gè)記錄包含鍵值對(duì)、記錄類型(Put / Merge / Delete)和校驗(yàn)和(checksum)。與 MemTable 不同,在 WAL 中,記錄不按 key 有序,而是按照請(qǐng)求到來(lái)的順序被追加到 WAL 中。

          7944336da83dbda8dc8f673203cc657b.webp

          WAL:為了應(yīng)對(duì)宕機(jī)的寫前日志

          Flush

          RocksDB 使用一個(gè)專門的后臺(tái)線程定期地把不可變的 MemTable 從內(nèi)存持久化到磁盤。一旦刷盤(flush)完成,不可變的 MemTable 和相應(yīng)的 WAL 就會(huì)被丟棄。RocksDB 開始寫入新的 WAL、MemTable。每次刷盤都會(huì)在 L0 層上產(chǎn)生一個(gè)新的 SST 文件。該文件一旦寫入磁盤后,就不再會(huì)修改。

          RocksDB 的 MemTable 的默認(rèn)基于跳表實(shí)現(xiàn)。該數(shù)據(jù)結(jié)構(gòu)是一個(gè)具有額外采樣層的鏈表,從而允許快速、有序地查詢和插入數(shù)據(jù)。有序性使得 MemTable 刷盤時(shí)更高效,因?yàn)榭梢灾苯影错樞虻I值對(duì)順序?qū)懭氪疟P。將隨機(jī)寫變?yōu)轫樞驅(qū)懯?LSM-Tree 的核心設(shè)計(jì)之一

          9e36ab785b680e4fa8539085593f1129.webp

          Flush:將不可變內(nèi)存表刷到磁盤的過(guò)程

          注:RocksDB 高度可配,因此你可以給 MemTable 配置其他的實(shí)現(xiàn)方案,RocksDB 中大部分組件都是如此。在其他的一些基于 LSM 實(shí)現(xiàn)的數(shù)據(jù)庫(kù)中,使用自平衡二叉搜索樹來(lái)實(shí)現(xiàn) MemTable 并不鮮見

          SST

          SST 文件包括從 MemTable 刷盤而來(lái)的鍵值對(duì),并且使用一種對(duì)查詢友好的數(shù)據(jù)格式來(lái)存儲(chǔ)。SST 是 Static Sorted Table 的縮寫(其他數(shù)據(jù)庫(kù)中也稱為 Sorted String Table)。它是一種基于塊( block) 的文件格式,會(huì)將數(shù)據(jù)切成固定大小的塊(默認(rèn)為 4KB)進(jìn)行存儲(chǔ)。RocksDB 支持各種壓縮 SST 文件的壓縮算法,例如 Zlib、BZ2、Snappy、LZ4 或 ZSTD 算法。與 WAL 的記錄類似,每個(gè)數(shù)據(jù)塊中都包含用于檢測(cè)數(shù)據(jù)是否損壞的校驗(yàn)和。每次從磁盤讀取數(shù)據(jù)時(shí),RocksDB 都會(huì)使用這些校驗(yàn)和進(jìn)行校驗(yàn)。

          SST 文件由幾個(gè)部分組成:首先是數(shù)據(jù)部分,包含一系列有序的鍵值對(duì)。key 的有序性可以讓我們對(duì) 其進(jìn)行增量編碼,也即,對(duì)于相鄰的 key ,我們可以只存其差值而非整個(gè) key。

          盡管 SST 中的 kv 對(duì)是有序的,我們也并非總能進(jìn)行二分查找,尤其是數(shù)據(jù)塊在壓縮過(guò)后,會(huì)使得查找很低效。RocksDB 使用索引來(lái)優(yōu)化查詢,存儲(chǔ)在緊鄰數(shù)據(jù)塊之后的索引塊。Index 會(huì)把每個(gè) block 數(shù)據(jù)中最后一個(gè) key 映射到它在磁盤上的對(duì)應(yīng)偏移量。同樣地,index 中的 key 也是有序的,因此我們可以通過(guò)二分搜索快速找到某個(gè) key。

          319d1498bc789d046df7b1b9994083d8.webp

          SST:?帶有索引的外存查找文件

          例如,我們?cè)诓檎?lynx,索引會(huì)告訴我們這個(gè)鍵值對(duì)可能在 block 2,因?yàn)榘凑兆值湫颍?code style="font-size:14px;color:rgb(30,107,184);background-color:rgba(27,31,35,.05);font-family:'Operator Mono', Consolas, Monaco, Menlo, monospace;">lynx 在 chipmunk 之后,但在 raccoon 之前。

          但其實(shí) SST 文件中并沒有 lynx,但我們?nèi)匀恍枰獜拇疟P加載 block 以進(jìn)行搜索。RocksDB 支持啟用布隆過(guò)濾器,一種具有高效空間利用率的概率性數(shù)據(jù)結(jié)構(gòu),可以用來(lái)檢測(cè)某個(gè)元素是否在集合中。布隆過(guò)濾器保存在 SST 文件中過(guò)濾器部分,以便能夠快速確定某個(gè) key 不在 SST 中(從而省去摸硬盤上的數(shù)據(jù)塊的開銷)。

          此外,SST 還有其他幾個(gè)不太有趣的部分,比如元數(shù)據(jù)部分。

          Compaction

          到現(xiàn)在為止,一個(gè)功能完備的鍵值存儲(chǔ)引擎講完了。但如果這樣直接上生產(chǎn)環(huán)境,會(huì)有一些問(wèn)題:空間放大(space amplifications)和讀放大(read amplifications)??臻g放大是存儲(chǔ)數(shù)據(jù)所用實(shí)際空間與邏輯上數(shù)據(jù)大小的比值。假設(shè)一個(gè)數(shù)據(jù)庫(kù)需要 2 MB 磁盤空間來(lái)存儲(chǔ)邏輯上的 1 MB 大小的鍵值對(duì)是,那么它的空間放大率是 2。類似地,讀放大用來(lái)衡量用戶執(zhí)行一次邏輯上的讀操作,系統(tǒng)內(nèi)所需進(jìn)行的實(shí)際 IO 次數(shù)。作為一個(gè)小練習(xí),你可以嘗試推演下什么是寫放大。

          現(xiàn)在,讓我們向數(shù)據(jù)庫(kù)添加更多 key 并刪除當(dāng)中的一些 key:

                db.delete("chipmunk")
          db.put("cat",?"5")
          db.put("raccoon",?"6")
          db.put("zebra",?"7")
          //?Flush?triggers
          db.delete("raccoon")
          db.put("cat",?"8")
          db.put("zebra",?"9")
          db.put("duck",?"10")

          22c7fab183b7403ac351f8dd82d78429.webp

          隨著我們的不斷寫入,MemTable 不斷被刷到磁盤,L0 上的 SST 文件數(shù)量也在增長(zhǎng):

          • 刪除或更新 key 所占用的空間永遠(yuǎn)不會(huì)被回收。例如,cat 這個(gè) key 的三次更新記錄分別在 SST1,SST2 和 SST3 中,而 chipmunk 在 SST1 中有一次更新記錄,在 SST2 中有一次刪除記錄,這些無(wú)用的記錄仍然占用額外磁盤空間。
          • 隨著 L0 上 SST 文件數(shù)量的增加,讀取變得越來(lái)越慢。每次查找都要逐個(gè)檢查所有 SST 文件。

          RocksDB 引入了壓實(shí)( Compaction )機(jī)制,可以降低空間放大和讀放大,但代價(jià)是更高的寫放大。Compaction 會(huì)將某層的 SST 文件同下一層的 SST 文件合并,并在這個(gè)過(guò)程中丟棄已刪除和被覆蓋的無(wú)效 key。Compaction 會(huì)在后臺(tái)專用的線程池中運(yùn)行,從而保證了 RocksDB 可以在做 Compaction 時(shí)能夠正常處理用戶的讀寫請(qǐng)求。

          d4339badd3b3d331b3b3cfa1f4e758ed.webp

          Leveled Compaction 是 RocksDB 中的默認(rèn) Compaction 策略。使用 Leveled Compaction,L0 層中的不同 SST 文件鍵范圍會(huì)重疊。L1 層及以下層會(huì)被組織為包含多個(gè) SST 文件的序列,并保證同層級(jí)內(nèi)的所有 SST 在鍵范圍上沒有交疊,且 SST 文件之間有序。Compaction 時(shí),會(huì)選擇性地將某層的 SST 文件與下一層的 key 范圍有重疊 SST 文件進(jìn)行合并。

          舉例來(lái)說(shuō),如下圖所示,在 L0 到 L1 層進(jìn)行 Compaction 時(shí),如果 L0 上的輸入文件覆蓋整個(gè)鍵范圍,此時(shí)就需要對(duì)所有 L0 和 L1 層的文件進(jìn)行 Compaction。

          e4f5b72ca77089982d671218feea6e71.webp

          而像是下面的這種 L1 和 L2 層的 Compaction,L1 層的輸入文件只與 L2 層的兩個(gè) SST 文件重疊,因此,只需要對(duì)部分文件進(jìn)行 Compaction 即可。

          aaea1dbfc7e596522db137dfb829cd50.webp

          當(dāng) L0 層上的 SST 文件數(shù)量達(dá)到一定閾值(默認(rèn)為 4)時(shí),將觸發(fā) Compaction。對(duì)于 L1 層及以下層級(jí),當(dāng)整個(gè)層級(jí)的 SST 文件總大小超過(guò)配置的目標(biāo)大小時(shí),會(huì)觸發(fā) Compaction 。當(dāng)這種情況發(fā)生時(shí),可能會(huì)觸發(fā) L1 到 L2 層的 Compaction。從而,從 L0 到 L1 層的 Compaction 可能會(huì)引發(fā)一直到最底層級(jí)聯(lián) Compaction。在 Compaction 完成之后,RocksDB 會(huì)更新元數(shù)據(jù)并從磁盤中刪除 已經(jīng)被 Compcated 過(guò)的文件。

          注:RocksDB 提供了不同 Compaction 策略來(lái)在空間、讀放大和寫放大之間進(jìn)行權(quán)衡。

          看到這里,你還記得上文提過(guò) SST 文件中的 key 是有序的嗎?有序性允許使用 K 路歸并算法逐步合并多個(gè) SST 文件。K 路歸并是兩路歸并的泛化版本,其工作方式類似于歸并排序的歸并階段。

          讀路徑

          使用持久化在磁盤上不可變的 SST 文件,讀路徑要比寫路徑簡(jiǎn)單很多。要找尋某個(gè) key,只需自頂而下遍歷 LSM—Tree。從 MemTable 開始,下探到 L0,然后繼續(xù)向更低層級(jí)查找,直到找到該 key 或者檢查完所有 SST 文件為止。

          以下是查找步驟:

          1. 檢索 MemTable。
          2. 檢索不可變 MemTables。
          3. 搜索最近 flush 過(guò)的 L0 層中的所有 SST 文件。
          4. 對(duì)于 L1 層及以下層級(jí),首先找到可能包含該 key 的單個(gè) SST 文件,然后在文件內(nèi)進(jìn)行搜索。

          搜索 SST 文件涉及:

          1. (可選)探測(cè)布隆過(guò)濾器。
          2. 查找 index 來(lái)找到可能包含這個(gè) key 的 block 所在位置。
          3. 讀取 block 文件并嘗試在其中找到 key。

          這就是全部所需步驟了!看看這個(gè) LSM-Tree:

          !https://-website-cn.oss-cn-hangzhou.aliyuncs.com/-blog/how-rocksdb-works/rocksdb-lookup.png

          根據(jù)待查找的 key 的具體情況,查找過(guò)程可能在上面任意步驟提前終止。例如,在搜索 MemTable 后,key “cat” 或 “chipmunk” 的查找工作會(huì)立即結(jié)束。查找 “raccoon” 則需要搜索 L1 為止,而查找根本不存在的 “manul” 則需要搜索整個(gè)樹。

          Merge

          RocksDB 還提供了一個(gè)同時(shí)涉及讀路徑和寫路徑的功能:合并(merge)操作。假設(shè),你在數(shù)據(jù)庫(kù)中存了一個(gè)整數(shù)列表,偶爾需要擴(kuò)展該列表。為了修改列表,你需要從數(shù)據(jù)庫(kù)中讀取其現(xiàn)有值,在內(nèi)存中更新該列表,最后把更新后的值寫回?cái)?shù)據(jù)庫(kù)。

          上面整個(gè)操作序列被稱為 “Read-Modify-Write” 循環(huán):

                db?=?open_db(path)

          //?讀取?Read
          old_val?=?db.get(key)?//?RocksDB?stores?keys?and?values?as?byte?arrays.?We?need?to?deserialize?the?value?to?turn?it?into?a?list.
          old_list?=?deserialize_list(old_val)?//?old_list:?[1,?2,?3]

          //?修改?Modify
          new_list?=?old_list.extend([4,?5,?6])?//?new_list:?[1,?2,?3,?4,?5,?6]
          new_val?=?serialize_list(new_list)

          //?寫回?Write
          db.put(key,?new_val)

          db.get(key)?//?deserialized?value:?[1,?2,?3,?4,?5,?6]

          上面這種方式能達(dá)到目的,但存在一些缺陷:

          • 非線程安全——兩個(gè)嘗試更新相同的 key 的不同線程,交錯(cuò)執(zhí)行,會(huì)出現(xiàn)更新丟失。
          • 存在寫放大——隨著值變得越來(lái)越大,更新成本也會(huì)增加。例如,在含有 100 個(gè)數(shù)的列表中追加一個(gè)整數(shù)需要讀取 100 個(gè)整數(shù)并將 101 個(gè)整數(shù)寫回。

          除了?Put?和?Delete?寫操作之外,RocksDB 還支持第三種寫操作?MergeMerge?操作需要提供?Merge?Operator——一個(gè)用戶定義函數(shù),負(fù)責(zé)將增量更新組合成單個(gè)值:

                funcmerge_operator(existing_val,?updates)?{
          ????????combined_list?=?deserialize_list(existing_val)
          ????????for?op?in?updates?{
          ????????????????combined_list.extend(op)
          ????????}
          ????????return?serialize_list(combined_list)
          }

          db?=?open_db(path,?{merge_operator:?merge_operator})
          //?key's?value?is?[1,?2,?3]

          list_update?=?serialize_list([4,?5,?6])
          db.merge(key,?list_update)

          db.get(key)?//?deserialized?value:?[1,?2,?3,?4,?5,?6]

          上面的?merge_operator?將傳遞給 Merge 調(diào)用的增量更新組合成一個(gè)單一值。當(dāng)調(diào)用 Merge 時(shí),RocksDB 僅將增量更新插入到 MemTable 和 WAL 中。之后,在 flush 和 compaction 時(shí),RocksDB 調(diào)用?merge_operator()?,在條件允許時(shí),將若干更新合并成單個(gè)更新或者單個(gè)值。在用戶調(diào)用?Get?或掃描讀取數(shù)據(jù)時(shí),如果發(fā)現(xiàn)任何待 merge 的更新,也會(huì)調(diào)用?merge_operator?向用戶返回一個(gè)經(jīng)過(guò) merge 而得到的值。

          Merge 非常適合于需要持續(xù)對(duì)已有值進(jìn)行少量更新的寫入密集型場(chǎng)景。那么,代價(jià)是什么?讀將變得更加昂貴——讀時(shí)的合并值沒有寫回。對(duì)該 key 的查詢需要一遍又一遍地執(zhí)行相同的合并過(guò)程,直到觸發(fā) flush 和 compaction 為止。與 RocksDB 其他部分一樣,我們可以通過(guò)限制 MemTable 中 merge 對(duì)象的數(shù)量、降低 L0 中 SST 文件數(shù)量來(lái)優(yōu)化讀行為。

          挑戰(zhàn)

          如果你的應(yīng)用對(duì)性能非常敏感,那么使用 RocksDB 面臨的最大挑戰(zhàn)是需要針對(duì)特定工作負(fù)載來(lái)進(jìn)行配置調(diào)優(yōu)。RocksDB 提供了非常多的可配置項(xiàng),但對(duì)其進(jìn)行合理調(diào)整通常需要理解數(shù)據(jù)庫(kù)內(nèi)部原理并深入研究 RocksDB 源代碼:

          “不幸的是,對(duì) RocksDB 進(jìn)行配置調(diào)優(yōu)并不容易。即使作為 RocksDB 開發(fā)人員的我們,也不能完全理解每個(gè)配置更改的所造成的影響。如果你想針對(duì)你的工作負(fù)載充分調(diào)優(yōu),我們建議你進(jìn)行實(shí)驗(yàn)和基準(zhǔn)測(cè)試,并時(shí)刻注意三個(gè)放大因素?!?/p>

          -- RocksDB ?官方調(diào)優(yōu)指南

          總結(jié)

          從零開始寫一個(gè)生產(chǎn)級(jí)別的 kv 存儲(chǔ)是非困難的:

          • 硬件和操作系統(tǒng)隨時(shí)都有可能丟失或損壞數(shù)據(jù)。
          • 性能優(yōu)化需要大量時(shí)間投入。

          RocksDB 解決了上述兩個(gè)問(wèn)題,從而讓你可以專注于上層業(yè)務(wù)邏輯實(shí)現(xiàn)。這也使得 RocksDB 成為構(gòu)建數(shù)據(jù)庫(kù)的優(yōu)秀模塊。

          題圖故事

          af2b22efdc09b86539dacef03edbdcb5.webp

          喀什老城的一個(gè)巷子里,各種鮮艷顏色的搭配LSM-Tree 更多文章推薦閱讀:漫談 LevelDB 數(shù)據(jù)結(jié)構(gòu)(一):跳表(Skip List)
          漫談 LevelDB 數(shù)據(jù)結(jié)構(gòu)(二):布隆過(guò)濾器(Bloom Filter)
          漫談 LevelDB 數(shù)據(jù)結(jié)構(gòu)(三):LRU 緩存( LRUCache)

          點(diǎn)擊“閱讀原文 ”可以跳轉(zhuǎn)我的小報(bào)童專欄,歡迎訂閱支持我的持續(xù)創(chuàng)作


          瀏覽 45
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  大香蕉精彩视频 | 亚洲精品在线中文字幕 | 风流老熟女一区二区三区 | 尻屄视频免费网站 | 国产精品18久久久 |