李潤(rùn)輝 古 亮 喻之斌
1(中國(guó)科學(xué)院深圳先進(jìn)技術(shù)研究院 深圳 518055)
2(深信服科技股份有限公司 深圳 518071)
近年來(lái),隨著移動(dòng)互聯(lián)網(wǎng)、人工智能及物聯(lián)網(wǎng)等新興技術(shù)的迅速發(fā)展,對(duì)海量數(shù)據(jù)的存儲(chǔ)需求也隨之變大,數(shù)據(jù)規(guī)模遠(yuǎn)超傳統(tǒng)業(yè)務(wù)。如,在安防領(lǐng)域,基于人工智能的人臉識(shí)別技術(shù)識(shí)別出視頻流中的人像,并以小文件/對(duì)象的形式保存在底層的文件/對(duì)象存儲(chǔ)系統(tǒng)中,從而產(chǎn)生每秒創(chuàng)建數(shù)千個(gè)文件/對(duì)象的業(yè)務(wù)流量峰值,遠(yuǎn)超傳統(tǒng)的監(jiān)控視頻存儲(chǔ),這對(duì)存儲(chǔ)系統(tǒng)的元數(shù)據(jù)訪問(wèn)性能和承載規(guī)模提出了嚴(yán)峻的考驗(yàn)。在存儲(chǔ)系統(tǒng)中,元數(shù)據(jù)的訪問(wèn)量遠(yuǎn)超數(shù)據(jù),且提供了并發(fā)控制等復(fù)雜邏輯,因此,元數(shù)據(jù)的訪問(wèn)性能和承載規(guī)模也決定了存儲(chǔ)系統(tǒng)的訪問(wèn)性能和承載規(guī)模的上限。
鍵值存儲(chǔ),是承載文件/對(duì)象存儲(chǔ)元數(shù)據(jù)等關(guān)鍵信息的存儲(chǔ)系統(tǒng)核心組件,對(duì)其訪問(wèn)性能和承載規(guī)模提升的研究具有重要意義。
分布式鍵值存儲(chǔ),具有更高的性能、更好的容錯(cuò)性和擴(kuò)展性,因而被廣泛使用。其將數(shù)據(jù)復(fù)制到多個(gè)存儲(chǔ)服務(wù)器的本地鍵值存儲(chǔ)引擎(簡(jiǎn)稱(chēng)“本地引擎”)上,并通過(guò)一致性協(xié)議來(lái)保證不同副本的一致性。在業(yè)界被廣泛應(yīng)用,且滿(mǎn)足強(qiáng)一致性的一致性協(xié)議(如 Paxos[1]、RAFT[2]),均基于日志復(fù)制。這類(lèi)一致性協(xié)議(簡(jiǎn)稱(chēng)“一致性協(xié)議”)在處理寫(xiě)請(qǐng)求時(shí),各副本首先持久化請(qǐng)求到本地的日志中,當(dāng)足夠多的副本寫(xiě)日志成功后,才將數(shù)據(jù)更新到存儲(chǔ)于本地引擎的狀態(tài)機(jī)中?;谌罩窘Y(jié)構(gòu)合并(Log-Structured Merge,LSM)樹(shù)的本地引擎(如 LevelDB[3]、RocksDB[4]),能夠?qū)⑿?I/O 轉(zhuǎn)化為順序追加寫(xiě)操作,對(duì)于底層硬件更為友好,因而被廣泛使用。使用 RAFT 等強(qiáng)一致性協(xié)議,及 RocksDB 等基于 LSM 樹(shù)的本地鍵值存儲(chǔ)作為本地引擎,成為了多個(gè)主流開(kāi)源分布式鍵值存儲(chǔ)系統(tǒng)(如TiKV[5]、Cassandra[6])的選擇。然而,為通用業(yè)務(wù)模型設(shè)計(jì)的本地引擎,其沒(méi)有充分適配一致性協(xié)議的訪問(wèn)模式,所以還存在較大的優(yōu)化空間。本文在分布式鍵值存儲(chǔ)的實(shí)踐中,發(fā)現(xiàn)并歸納出了如下問(wèn)題:
(1)基于 LSM 樹(shù)的本地引擎為了提供容錯(cuò)性,會(huì)將請(qǐng)求先寫(xiě)入在本地持久化的預(yù)寫(xiě)式日志(Write-ahead log,WAL)中,再更新內(nèi)存數(shù)據(jù)。當(dāng)系統(tǒng)發(fā)生異常重啟時(shí),本地引擎可以通過(guò)WAL 修復(fù)丟失的內(nèi)存數(shù)據(jù)。然而,一致性協(xié)議的日志,也具備通過(guò)回放修復(fù)狀態(tài)機(jī)至最新?tīng)顟B(tài)的能力。此時(shí),修復(fù)同一份數(shù)據(jù),需要兩次持久化的保護(hù),這一雙寫(xiě)會(huì)帶來(lái)高達(dá) 47.5% 的性能損耗(見(jiàn)第 5.3 節(jié))。能否通過(guò)改造底層引擎,配合一致性協(xié)議,消除雙寫(xiě),來(lái)達(dá)到提升分布式鍵值存儲(chǔ)性能的目的呢?
(2)一致性協(xié)議的修復(fù)方法有兩種:通過(guò)重放日志進(jìn)行增量修復(fù),以及復(fù)制狀態(tài)機(jī)進(jìn)行全量修復(fù)。其中,全量修復(fù)需要?jiǎng)h除舊狀態(tài)機(jī),并從其他節(jié)點(diǎn)復(fù)制新?tīng)顟B(tài)機(jī)。LSM 樹(shù)的刪除操作異步回收空間,導(dǎo)致新舊狀態(tài)機(jī)數(shù)據(jù)長(zhǎng)期并存,直到舊狀態(tài)機(jī)數(shù)據(jù)全部被異步刪除,這樣會(huì)造成存儲(chǔ)空間浪費(fèi)嚴(yán)重。在實(shí)驗(yàn)中,全量修復(fù)會(huì)帶來(lái)超過(guò) 60% 的空間浪費(fèi)(見(jiàn)第 5.3 節(jié))。為維持系統(tǒng)的正常運(yùn)行,存儲(chǔ)服務(wù)器必須在物理設(shè)備尚余大量存儲(chǔ)空間的情況下,就停止服務(wù),以防全量修復(fù)耗盡存儲(chǔ)空間,預(yù)留空間造成存儲(chǔ)容量的嚴(yán)重浪費(fèi)。能否通過(guò)對(duì)底層引擎的改造,使得全量修復(fù)過(guò)程能夠?qū)崟r(shí)回收空間,消除空間放大,從而避免預(yù)留過(guò)多的空間呢?
為了解決以上兩個(gè)問(wèn)題,本文提出了基于LSM 樹(shù)改進(jìn)的 PheonixLSM 本地引擎。具體貢獻(xiàn)如下:(1)通過(guò)增加 LSM 樹(shù)的增刪改操作和內(nèi)存數(shù)據(jù)回刷順序的制約,并提供新的查詢(xún)接口,使得一致性協(xié)議日志能夠同時(shí)起到 WAL 的作用,恢復(fù)本地引擎的內(nèi)存數(shù)據(jù),從而避免日志和WAL 的雙寫(xiě),同時(shí)可將上層分布式鍵值存儲(chǔ)吞吐提高 90% 以上,單位計(jì)算資源吞吐提高 20%以上。(2)通過(guò)改造 LSM 樹(shù)的底層數(shù)據(jù)組織形式和范圍刪除邏輯,使得在對(duì)舊狀態(tài)機(jī)的刪除操作中,能夠?qū)崟r(shí)回收空間,使全量修復(fù)過(guò)程中的空間放大從 65.6% 降低到 6.4%,并節(jié)省 72.3% 的修復(fù)時(shí)間。
本文后續(xù)內(nèi)容的組織如下:第 2 節(jié)列舉相關(guān)工作;第 3 節(jié)介紹技術(shù)背景;第 4 節(jié)說(shuō)明PheonixLSM 的設(shè)計(jì);第 5 節(jié)說(shuō)明 PheonixLSM的原型實(shí)現(xiàn)和部署,實(shí)驗(yàn)結(jié)果以及分析;第 6 節(jié)對(duì)本工作進(jìn)行了討論分析;第 7 節(jié)總結(jié)全文。
本節(jié)首先列舉了常見(jiàn)的本地鍵值存儲(chǔ)系統(tǒng)以及核心數(shù)據(jù)結(jié)構(gòu),然后對(duì) LSM 樹(shù)的優(yōu)化改造方向進(jìn)行了歸納。
本地引擎有多種形態(tài),有將數(shù)據(jù)存儲(chǔ)于內(nèi)存的 Redis[7]、Memcached[8]和 MemC3[9]等,也有將數(shù)據(jù)持久化于本地存儲(chǔ)(機(jī)械硬盤(pán)或固態(tài)硬盤(pán))的 LevelDB[3]和 RocksDB[4]等。B+ 樹(shù)[10]和 LSM樹(shù)是兩種常見(jiàn)的持久化引擎的核心數(shù)據(jù)結(jié)構(gòu)。B+ 樹(shù)的數(shù)據(jù)全量存儲(chǔ)在首尾相連的葉子節(jié)點(diǎn)中,具有良好的讀和范圍查找性能,MySQL 的本地引擎 MyISAM[11]、InnoDB[12]等都基于 B+樹(shù)。然而,B+ 樹(shù)不適用于隨機(jī)插入操作,其會(huì)產(chǎn)生大量的隨機(jī)小 I/O。相比之下,LSM 樹(shù)能將隨機(jī)小 I/O 轉(zhuǎn)為連續(xù)大 I/O,寫(xiě)性能較好,且能較好地平衡讀放大、寫(xiě)放大和空間放大,近年來(lái)得到了廣泛應(yīng)用。LSM 樹(shù)最早應(yīng)用在 Google推出的 LevelDB[3]中,被用作核心數(shù)據(jù)結(jié)構(gòu),F(xiàn)acebook 此后推出了 RocksDB[4],該結(jié)構(gòu)在LevelDB 的基礎(chǔ)上針對(duì)固態(tài)盤(pán)做了許多優(yōu)化。
近年來(lái),基于 LSM 樹(shù)的存儲(chǔ)引擎被廣泛應(yīng)用在 Facebook[13-14]等企業(yè)的諸多場(chǎng)景中。關(guān)于 LSM 樹(shù)的寫(xiě)放大問(wèn)題:PebblesDB[15]放寬了LSM 樹(shù)的約束,使 L1及更低層中,SST 文件的 key 范圍可以適度重合,從而降低寫(xiě)放大;WiscKey[16]采用了鍵值分離的策略,解決大 value帶來(lái)的索引效率低,以及寫(xiě)放大嚴(yán)重的問(wèn)題。關(guān)于 LSM 樹(shù)如何適配新硬件:增加 NVMeSSD 作為緩存層提升性能[17],使用 FPGA 卸載合并任務(wù),減少對(duì)讀寫(xiě)業(yè)務(wù)的影響[18]等。關(guān)于 LSM 樹(shù)讀性能:采用動(dòng)態(tài)布隆過(guò)濾器減少磁盤(pán) I/O[19],針對(duì) LSM 樹(shù)的數(shù)據(jù)結(jié)構(gòu)開(kāi)發(fā)新緩存策略[20],優(yōu)化范圍查詢(xún)中的讀放大[21],調(diào)度后臺(tái)回刷合并工作以減少對(duì)上層業(yè)務(wù)的干擾,降低尾時(shí)延[22]等。
本節(jié)首先介紹分布式鍵值存儲(chǔ)的主要組成部分,然后介紹 LSM 樹(shù)的基礎(chǔ),最后以 RAFT 為例介紹基于日志復(fù)制的一致性協(xié)議。
分布式鍵值存儲(chǔ)將鍵值對(duì)存儲(chǔ)在通過(guò)網(wǎng)絡(luò)互相連接的存儲(chǔ)服務(wù)器上,從系統(tǒng)架構(gòu)上分為 3個(gè)主要組件:分布式路由、一致性協(xié)議和本地引擎。
圖 1 是一個(gè)典型的分布式鍵值存儲(chǔ)的架構(gòu)及請(qǐng)求處理流程。分布式路由模塊將 key 空間映射到多個(gè)復(fù)制組,任意 key 都會(huì)被映射到唯一的復(fù)制組。如,當(dāng)寫(xiě)入鍵值對(duì)
圖1 分布式鍵值存儲(chǔ)架構(gòu)及請(qǐng)求處理流程Fig. 1 Architecture of distributed key-value storage and the request processing flow
LSM 樹(shù)的結(jié)構(gòu)及鍵值對(duì)生命周期如圖 2所示,其主要由 3 部分組成:內(nèi)存數(shù)據(jù)結(jié)構(gòu)Memtables,以及持久化的 WAL 和 SST 文件。SST 文件被組織成不同的層(L0層、L1層等)。
圖2 LSM 樹(shù)以及鍵值對(duì)的生命周期Fig. 2 LSM-tree and lifecycle of key-value pairs
寫(xiě)請(qǐng)求首先持久化到 WAL 中,之后鍵值對(duì)被插入全局唯一的可讀寫(xiě) Memtable 中,請(qǐng)求完成。當(dāng)可讀寫(xiě) Memtable 中的數(shù)據(jù)量超過(guò)一個(gè)閾值時(shí),其轉(zhuǎn)為只讀,后續(xù)請(qǐng)求的鍵值對(duì)被寫(xiě)入新的可讀寫(xiě) Memtable 中。只讀 Memtables 中的鍵值對(duì)會(huì)在后臺(tái)的回刷和合并操作中逐層下沉至底層。
合并操作選擇 Li-1(i≥1)層的某些 SST 文件,以及 Li層與該 SST 文件的 key 區(qū)間有重合的 SST 文件。合并后的鍵值對(duì),將按 key 的字典序?qū)懭胄碌?Li層的 SST 文件中,當(dāng) Li-1及 Li層中都有某個(gè) key 的鍵值對(duì)時(shí),在合并操作后只有最新的鍵值對(duì)會(huì)被保留,SST 文件視圖更新,舊SST 文件被刪除。
查詢(xún)操作會(huì)按寫(xiě)入從新至舊的順序依次查找 Memtables 和 L0中的各 SST 文件,然后從 L1開(kāi)始逐層向下查找。當(dāng)查找到對(duì)應(yīng) key 的鍵值對(duì)時(shí),查詢(xún)操作完成。若查詢(xún)至底層時(shí)仍沒(méi)有與之對(duì)應(yīng)的鍵值對(duì)時(shí),則返回 key 不存在。
LSM 樹(shù)的刪除請(qǐng)求和寫(xiě)請(qǐng)求流程相同,但是刪除請(qǐng)求插入的是一條存儲(chǔ)特殊 value 的墓碑鍵值對(duì)。當(dāng)查詢(xún)操作讀到墓碑鍵值對(duì)時(shí),立即返回 key 不存在(如圖 2 中的 foo2)。范圍刪除采用同樣的方法,插入一個(gè)特殊的范圍刪除墓碑鍵值對(duì),當(dāng)查詢(xún)的 key 在該墓碑標(biāo)記的范圍內(nèi)時(shí),則返回 key 不存在(如圖 2 所示,當(dāng)查詢(xún) foo6 時(shí),由于其處于范圍刪除墓碑鍵值對(duì)[foo5, foo9]的范圍內(nèi),因此查詢(xún)也會(huì)返回 key 不存在)。
一致性協(xié)議為復(fù)制組提供了強(qiáng)一致性保證,使復(fù)制組即使在故障場(chǎng)景下,依然能夠?qū)ν馓峁┮恢碌臓顟B(tài)機(jī)視圖。本文以 RAFT 協(xié)議為例對(duì)一致性協(xié)議的基本原理作簡(jiǎn)要說(shuō)明①:本文雖然以 RAFT 作為一致性協(xié)議的代表進(jìn)行說(shuō)明,但本文中的技術(shù)同樣適用于其他的基于日志復(fù)制的一致性協(xié)議。。
RAFT 協(xié)議定義了一個(gè)復(fù)制組中若干節(jié)點(diǎn)的交互行為。在穩(wěn)定狀態(tài)下,復(fù)制組中有一個(gè)主節(jié)點(diǎn)和若干個(gè)從節(jié)點(diǎn)。每個(gè)節(jié)點(diǎn)中有一致性模塊、日志和狀態(tài)機(jī) 3 個(gè)主要組件。狀態(tài)機(jī)是一個(gè)抽象概念,其在分布式鍵值存儲(chǔ)中是本地引擎的鍵值對(duì)集合。
圖 3 為 RAFT 協(xié)議處理增刪改操作的流程。請(qǐng)求首先被發(fā)送至主節(jié)點(diǎn)(步驟 1),主節(jié)點(diǎn)的一致性模塊為其分配一個(gè)系統(tǒng)生命周期遞增的日志索引,并將請(qǐng)求轉(zhuǎn)發(fā)至各從節(jié)點(diǎn)(步驟 2)。主節(jié)點(diǎn)和各從節(jié)點(diǎn)將請(qǐng)求持久化到日志中,并返回主節(jié)點(diǎn)的一致性模塊日志寫(xiě)入成功(步驟 3)。當(dāng)大部分節(jié)點(diǎn)返回成功后,主節(jié)點(diǎn)會(huì)將請(qǐng)求應(yīng)用到狀態(tài)機(jī)上(步驟 4),并返回請(qǐng)求處理成功(步驟 5)。主節(jié)點(diǎn)在后續(xù)和從節(jié)點(diǎn)的交互中,指示從節(jié)點(diǎn)異步應(yīng)用對(duì)應(yīng)日志(步驟 6)。
圖3 RAFT 協(xié)議處理增刪改操作的流程Fig. 3 Work flow of RAFT consensus algorithm
RAFT 協(xié)議通過(guò)保持各復(fù)制組中節(jié)點(diǎn)日志的一致性,達(dá)到各節(jié)點(diǎn)狀態(tài)機(jī)保持一致的目的。通過(guò)重放相同的日志,各復(fù)制組得到相同的狀態(tài)機(jī)。在實(shí)際系統(tǒng)中,狀態(tài)機(jī)會(huì)定時(shí)進(jìn)行持久化,保存為一個(gè)狀態(tài)機(jī)快照,即快照操作。當(dāng)進(jìn)行快照操作時(shí),需要記錄快照索引,即狀態(tài)機(jī)最新應(yīng)用的日志索引。當(dāng)故障重啟時(shí),一致性模塊加載狀態(tài)機(jī)快照,并順序重放索引大于快照索引的日志,修復(fù)出最新的狀態(tài)機(jī),這一過(guò)程叫作增量修復(fù)。使用快照和大于快照索引的日志,便可修復(fù)出最新的狀態(tài)機(jī),所以小于等于最新快照索引的日志均可以被安全截?cái)唷?/p>
當(dāng)節(jié)點(diǎn)長(zhǎng)期離線后再上線,或遷移到新的存儲(chǔ)服務(wù)器時(shí),主節(jié)點(diǎn)的日志可能無(wú)法滿(mǎn)足其修復(fù)(或新建)狀態(tài)機(jī)的需求。如,某節(jié)點(diǎn)最新應(yīng)用的日志索引為 100,然而主節(jié)點(diǎn)維護(hù)的最舊日志索引為 110。那么,必須先從主節(jié)點(diǎn)同步其狀態(tài)機(jī)快照至本地,然后從主節(jié)點(diǎn)同步并順序重放索引大于快照索引的日志來(lái)修復(fù)狀態(tài)機(jī)。這一過(guò)程叫作全量修復(fù)。
此外,分布式鍵值存儲(chǔ)中,狀態(tài)機(jī)已經(jīng)持久化存儲(chǔ)在本地引擎中,所以快照操作并不需要額外持久化狀態(tài)機(jī),只需要記錄快照索引即可,這種快照操作稱(chēng)作隱式快照。
本節(jié)將對(duì) PheonixLSM 的系統(tǒng)設(shè)計(jì)進(jìn)行介紹。針對(duì)前述的日志和 WAL 雙寫(xiě),以及全量修復(fù)時(shí)空間放大兩個(gè)問(wèn)題,提出雙寫(xiě)消除和過(guò)期數(shù)據(jù)實(shí)時(shí)清理兩項(xiàng)優(yōu)化。
本小節(jié)說(shuō)明如何使用 RAFT 日志進(jìn)行狀態(tài)機(jī)的同步,同時(shí)在本地引擎中,起到重建由進(jìn)程重啟導(dǎo)致丟失 Memtables 的作用。在滿(mǎn)足該前提的情況下,PheonixLSM 不需要 WAL 保護(hù),所以可通過(guò)關(guān)閉 WAL 消除雙寫(xiě)。
關(guān)閉 WAL 之后,本地引擎由于失去保護(hù),重啟會(huì)導(dǎo)致所有的 Memtables 丟失且無(wú)法重建,只留下 SST 文件。本文歸納出使用日志修復(fù)Memtables 的充分條件:在任何時(shí)刻,已持久化的 SST 文件都能構(gòu)成一個(gè)狀態(tài)機(jī)快照。在滿(mǎn)足該充分條件的情況下,關(guān)掉 WAL 的本地引擎在任意時(shí)刻重啟后都存儲(chǔ)一個(gè)狀態(tài)機(jī)快照。根據(jù)一致性協(xié)議的性質(zhì)可知,只要大于該快照索引的日志沒(méi)有被刪除,那么在該快照的基礎(chǔ)上,就可以通過(guò)回放日志恢復(fù)狀態(tài)機(jī)。
為了關(guān)閉 WAL,需要解決以下兩個(gè)問(wèn)題:(1)如何保證在任意時(shí)刻,已持久化的 SST 文件都能構(gòu)成一個(gè)狀態(tài)機(jī)快照;(2) 在滿(mǎn)足(1)的情況下,如何獲得上述狀態(tài)機(jī)快照的快照索引。從該快照索引對(duì)應(yīng)的下一條 RAFT Log 開(kāi)始回放,就能夠重構(gòu)出狀態(tài)機(jī)。
為解決上述問(wèn)題,PheonixLSM 改造了增刪改請(qǐng)求的應(yīng)用流程。原來(lái)的應(yīng)用流程:將每個(gè)增刪改請(qǐng)求產(chǎn)生的鍵值對(duì)提交到本地引擎;改造后的應(yīng)用流程:除增刪改請(qǐng)求產(chǎn)生的鍵值對(duì)之外,還需同時(shí)寫(xiě)入一個(gè)特殊的哨兵鍵值對(duì)。哨兵鍵值對(duì)在一個(gè)復(fù)制組中有且僅有一個(gè),其 value 是當(dāng)前最新被應(yīng)用的 RAFT 日志索引,能夠確定重啟時(shí)本地引擎中狀態(tài)機(jī)的快照索引。圖 4 為PheonixLSM 中哨兵鍵值對(duì)插入 Memtable 并持久化至 SST 文件的流程,由于關(guān)閉了 WAL,插入Memtable 時(shí)只需要內(nèi)存操作。
若僅依靠哨兵鍵值對(duì),則無(wú)法保證重啟后已持久化的 SST 文件能夠構(gòu)成一個(gè)狀態(tài)機(jī)快照。所以 PheonixLSM 還對(duì)增刪改和回刷操作做了以下約束:
(1)一個(gè)請(qǐng)求的所有鍵值對(duì)(包括普通鍵值對(duì)、墓碑鍵值對(duì)和哨兵鍵值對(duì)),必須更新至同一 Memtable 中;
(2)Memtables 必須按照其轉(zhuǎn)為只讀的時(shí)間順序順次進(jìn)行回刷。
為了使 PheonixLSM 能夠指導(dǎo)狀態(tài)機(jī)日志的截?cái)嗖僮?,新增?GetPersisted 接口,其可跨過(guò)Memtables,直接從 L0開(kāi)始查找已持久化的鍵值對(duì)。通過(guò) GetPersisted 接口查找哨兵鍵值對(duì),返回的結(jié)果即是 SST 文件構(gòu)成的狀態(tài)機(jī)快照的快照索引。如圖 4 所示,GetPersisted 接口查找到的哨兵鍵值對(duì)的值為 700。這一返回結(jié)果表明,在沒(méi)有新回刷發(fā)生的情況下發(fā)生故障重啟,那么本地引擎中存儲(chǔ)的是快照索引為 700 的狀態(tài)機(jī)快照。因此,日志索引小于等于 700 的日志,此時(shí)都可以被安全地刪除。
圖4 PheonixLSM 中哨兵鍵值對(duì)插入 Memtable 并持久化至 SST 文件的流程Fig. 4 Sentinel key-value pairinserting into Memtable and persisted to SST files
本文通過(guò)實(shí)驗(yàn)證明了上述雙寫(xiě)消除方案的有效性。假設(shè)本地引擎采取了前述的寫(xiě)操作和回刷操作約束,使用 GetPersisted 接口獲得哨兵值為idx,可以得出下述引理和定理。
引理1所有滿(mǎn)足日志索引index≤idx的請(qǐng)求數(shù)據(jù)都已經(jīng)持久化,所有日志索引index>idx的請(qǐng)求數(shù)據(jù)重啟前在 Memtables 中,沒(méi)有回刷,已經(jīng)在重啟中丟失。
證明:首先使用反證法證明index≤idx的所有請(qǐng)求數(shù)據(jù)都已持久化。假如存在某日志索引index'<idx的請(qǐng)求沒(méi)有持久化,那么,日志index'和idx的請(qǐng)求數(shù)據(jù)一定寫(xiě)入了不同的 Memtables中,否則會(huì)被同時(shí)持久化②:Memtable 回刷的原子性:Memtable 持久化成一個(gè) L0 層 SST 文件的過(guò)程并不是原子的,此時(shí)斷電可能導(dǎo)致只有 Memtable 中部分的數(shù)據(jù)刷入該 SST 中。然而,Memtable 回刷的過(guò)程是由(1)Memtable 數(shù)據(jù)寫(xiě)入 SST 文件,(2)寫(xiě)入新的 LSM 樹(shù)視圖文件(各 SST 文件的文件名、key 區(qū)間,以及 SST 文件的層次關(guān)系等信息),(3)替換舊 LSM 樹(shù)視圖文件 3 個(gè)步驟完成的。上述斷電發(fā)生在步驟(1),重啟之后,LSM 樹(shù)的視圖未被更新,被寫(xiě)入一半的 SST 文件不在舊視圖中,會(huì)在初始化過(guò)程中被直接刪除。而步驟(3)的替換視圖文件是原子操作,因此,回刷操作中發(fā)生故障,一個(gè) Memtable 中的數(shù)據(jù),或者全部丟失,或者全部已經(jīng)持久化,顯示在新的視圖文件中,不會(huì)出現(xiàn)一個(gè) Memtable 部分?jǐn)?shù)據(jù)持久化,部分?jǐn)?shù)據(jù)丟失的場(chǎng)景。;假設(shè)日志index'和idx的請(qǐng)求數(shù)據(jù)分別被寫(xiě)入了 MemtablesMi和Mj,那么由于index'<idx,一致性協(xié)議保證請(qǐng)求數(shù)據(jù)按日志索引從小到大的順序?qū)懭氡镜匾?,因此,日志index'的數(shù)據(jù)會(huì)早于idx的數(shù)據(jù)被寫(xiě)入。由于任何時(shí)刻,本地引擎都只有唯一的可讀寫(xiě) Memtable,那么Mi早于Mj轉(zhuǎn)為只讀。索引日志index'的請(qǐng)求數(shù)據(jù)沒(méi)有持久化,而idx的已被持久化,說(shuō)明Mi晚于Mj回刷,違反了前述的回刷順序約束。因此,假設(shè)不成立,所有日志索引index≤idx的請(qǐng)求數(shù)據(jù)都已持久化。
類(lèi)似地,也可以證明所有日志索引index>idx的日志尚沒(méi)有持久化。
定理1在滿(mǎn)足寫(xiě)和回刷約束的前提下,如果發(fā)生重啟,重啟后的本地引擎中存儲(chǔ)的是快照日志索引為idx的狀態(tài)機(jī)快照。
證明:根據(jù)引理 1,當(dāng)發(fā)生故障重啟時(shí),所有日志索引index≤idx的請(qǐng)求數(shù)據(jù)均已被持久化,而index>idx的請(qǐng)求數(shù)據(jù)在重啟前,只是存儲(chǔ)在 Memtables 中沒(méi)有回刷,在重啟過(guò)程中已經(jīng)丟失。按照一致性協(xié)議的定義,所有日志索引index≤idx的請(qǐng)求數(shù)據(jù),在本地引擎中,已經(jīng)全部被順序持久化,并且沒(méi)有多余的請(qǐng)求數(shù)據(jù)被寫(xiě)入。所以,本地引擎中存儲(chǔ)的是快照索引為idx的狀態(tài)機(jī)快照。
刪除舊狀態(tài)機(jī)是分布式鍵值存儲(chǔ)的常見(jiàn)操作。節(jié)點(diǎn)長(zhǎng)期離線后再上線觸發(fā)全量修復(fù),以及負(fù)載均衡過(guò)程中,復(fù)制組節(jié)點(diǎn)遷入新服務(wù)器時(shí),都需要先刪除舊狀態(tài)機(jī),以防污染新?tīng)顟B(tài)機(jī)數(shù)據(jù)。為便于操作,分布式鍵值存儲(chǔ)通常將不同復(fù)制組的 key 轉(zhuǎn)換為不同前綴的底層格式。在本文的系統(tǒng)實(shí)現(xiàn)中,業(yè)務(wù)邏輯的 key 都使用其所屬的復(fù)制組編號(hào)作為前綴,然后再存入本地引擎(如圖 4 所示)。這種轉(zhuǎn)換使得相同復(fù)制組中的 key在底層引擎中具有相同的前綴,存儲(chǔ)在連續(xù)空間中,可以通過(guò)范圍刪除清理某復(fù)制組的狀態(tài)機(jī)。
原生本地引擎在刪除舊狀態(tài)機(jī)時(shí),插入了一個(gè)表示范圍刪除的墓碑鍵值對(duì),然后,將從主節(jié)點(diǎn)處復(fù)制來(lái)的新?tīng)顟B(tài)機(jī)快照插入。如圖 5 所示,由于墓碑鍵值對(duì)通過(guò)逐層合并至最低層才能完全回收空間,所以在新?tīng)顟B(tài)機(jī)插入后的較長(zhǎng)時(shí)間內(nèi),新舊狀態(tài)機(jī)數(shù)據(jù)在本地引擎中共存,將會(huì)造成存儲(chǔ)空間的浪費(fèi)。PheonixLSM 針對(duì)這一問(wèn)題,提出將各復(fù)制組的數(shù)據(jù)大致隔離在不同的 SST 文件中,從而使得刪除狀態(tài)機(jī)的操作可以通過(guò)同步刪除相關(guān)的 SST 文件完成,實(shí)時(shí)釋放空間。
圖5 原生本地引擎的全量修復(fù)流程和其造成的空間放大Fig. 5 Full-node repair with original local engine and the spatial amplification it caused
PheonixLSM 通過(guò)改造 LSM 樹(shù)的合并邏輯,來(lái)達(dá)成上述復(fù)制組數(shù)據(jù)的隔離。LSM 樹(shù)原有的合并邏輯,將 Li和 Li+1層中的候選 SST 文件的鍵值對(duì)分別按順序讀取出來(lái),并將兩層的鍵值對(duì)進(jìn)行合并后寫(xiě)入新的 Li+1層的 SST 文件。PheonixLSM 修改后的合并流程中,會(huì)根據(jù)鍵值對(duì) key 的前綴判斷其所屬的復(fù)制組,當(dāng)處理的復(fù)制組發(fā)生改變時(shí)(如,剛剛處理的 key 為 002_foo1,而正在處理的 key 為 003_foo2,說(shuō)明復(fù)制組 002 的數(shù)據(jù)已經(jīng)被寫(xiě)完,開(kāi)始寫(xiě)復(fù)制組 003 的數(shù)據(jù)),PheonixLSM 會(huì)將當(dāng)前 SST 文件關(guān)閉,并將當(dāng)前鍵值對(duì)寫(xiě)入新的 SST 文件。從而保證,在L1及更低層的任何 SST 文件中,都只包含屬于某一個(gè)復(fù)制組的鍵值對(duì)。
圖 6 是使用 PheonixLSM 進(jìn)行本地引擎的舊狀態(tài)機(jī)刪除,以及新?tīng)顟B(tài)機(jī)快照的安裝流程。刪除舊狀態(tài)機(jī)時(shí),首先強(qiáng)制回刷 Memtables,并在回刷后將 L0的 SST 文件合并至 L1。此時(shí),所有屬于該狀態(tài)機(jī)的鍵值對(duì)都存儲(chǔ)在某個(gè) SST 文件集合中,且該集合中的 SST 文件不包含其他復(fù)制組的狀態(tài)機(jī)數(shù)據(jù)。刪除操作可直接刪除復(fù)制組所有相關(guān)的 SST 文件。
PheonixLSM 在刪除狀態(tài)機(jī)時(shí)(圖 6(b)~(c)),遍歷 LSM 樹(shù)視圖中的 L1層及以下各 SST 文件,視圖中保存了每個(gè) SST 文件的 key 區(qū)間。當(dāng)某SST 文件包含前綴為目標(biāo)復(fù)制組編號(hào)的 key 時(shí),說(shuō)明該 SST 文件中保存的都是目標(biāo)復(fù)制組中的數(shù)據(jù),就可以進(jìn)行刪除操作(圖 6(c))。刪除舊狀態(tài)機(jī)之后空間被完全回收,新?tīng)顟B(tài)機(jī)快照在此時(shí)進(jìn)行安裝(圖 6(d))。
圖6 使用 PheonixLSM 進(jìn)行全量修復(fù)的舊狀態(tài)機(jī)刪除和新?tīng)顟B(tài)機(jī)快照的安裝流程Fig. 6 Full-node repair process with PhoenixLSM, including deleting old state machine and instralling new one
一致性模塊的修復(fù)操作,需要先將狀態(tài)機(jī)快照安裝完畢,才能重放日志,因此,在刪除舊狀態(tài)機(jī)并插入新?tīng)顟B(tài)機(jī)快照的過(guò)程中,本地引擎不會(huì)收到該復(fù)制組的請(qǐng)求。刪除流程可以確保在強(qiáng)制回刷合并至 L1之后,復(fù)制組的所有鍵值對(duì)都已經(jīng)在 L1或更低層。PheonixLSM 的刪除操作,能將舊的狀態(tài)機(jī)完全刪除,且其他復(fù)制組不受影響。
PheonixLSM 的原型基于 RocksDB 5.18.0 實(shí)現(xiàn),對(duì) RocksDB 的代碼庫(kù)僅有約 200 行代碼的改動(dòng)。具體的改造方法見(jiàn)第 4 節(jié)。
在實(shí)際部署中,PheonixLSM 作為自研分布式鍵值存儲(chǔ)系統(tǒng) PheonixKV 的本地引擎。如圖 7所示,PheonixKV 有 3 個(gè)主要組件:數(shù)據(jù)服務(wù)器KVAgent、元數(shù)據(jù)服務(wù)器 MetaServer 和客戶(hù)端。
圖7 PheonixKV 架構(gòu)Fig. 7 PheonixKV architecture
PheonixKV 將 key 空間映射到若干個(gè)使用 RAFT 協(xié)議維護(hù)一致性的復(fù)制組。復(fù)制組的節(jié)點(diǎn)分布在不同的 KVAgent 上,以提供容錯(cuò)性。KVAgent 負(fù)責(zé)本地引擎和復(fù)制組節(jié)點(diǎn)的初始化,本地資源的分配和清理等,并定期心跳向 MetaServer 匯報(bào)健康狀況。MetaServer 根據(jù)集群健康和負(fù)載狀況,通過(guò)心跳回復(fù)指示對(duì)應(yīng) KVAgent 執(zhí)行節(jié)點(diǎn)遷移。KVAgent 通過(guò)GetPersisted 接口從 PheonixLSM 獲取最新持久化的日志索引,指導(dǎo)日志截?cái)?。MetaServer 集群也使用 RAFT 協(xié)議來(lái)維護(hù)關(guān)鍵元數(shù)據(jù)的一致性。客戶(hù)端先向 MetaServer 請(qǐng)求路由信息,包括復(fù)制組所在的 KVAgent 列表,以及 key 到復(fù)制組的映射規(guī)則,之后根據(jù)路由信息將請(qǐng)求發(fā)至對(duì)應(yīng)的KVAgent 處理。
本實(shí)驗(yàn)是在一個(gè)三主機(jī)的集群環(huán)境上進(jìn)行的,每臺(tái)主機(jī)配備一顆 14 核 2.40 GHz 的 Intel Xeon E5 2680 v4CPU,128 MiB 內(nèi)存,以及兩塊 480 GiB 的 Intel S4600 SATA SSD。3 臺(tái)主機(jī)通過(guò) 10 Gbps 的網(wǎng)絡(luò)連接。每臺(tái)主機(jī)運(yùn)行兩個(gè)KVAgent 以及一個(gè) MetaServer。每個(gè) KVAgent 管理其獨(dú)占的 SSD,故單 SSD 故障只會(huì)影響一個(gè)KVAgent。PheonixKV 系統(tǒng)中有 256 個(gè)三副本復(fù)制組,其節(jié)點(diǎn)分布在不同主機(jī)的 KVAgent 上,提供主機(jī)級(jí)別的故障域。
本實(shí)驗(yàn)使用 RocksDB 自帶的 db_bench 測(cè)試本地引擎,并使用自主研發(fā)的 PheonixKVTest 測(cè)試工具測(cè)試 PheonixKV 性能。PheonixKVTest 使用指定并發(fā)數(shù)執(zhí)行鍵值對(duì)的插入、刪除、讀取和校驗(yàn)操作,同時(shí)可監(jiān)控性能,實(shí)時(shí)輸出當(dāng)前的時(shí)延和吞吐數(shù)據(jù)。PheonixKV 的目標(biāo)是承載新型視頻監(jiān)控系統(tǒng)產(chǎn)生的對(duì)象存儲(chǔ)元數(shù)據(jù),該業(yè)務(wù)模型會(huì)高并發(fā)寫(xiě)入約為 256 字節(jié)的鍵值對(duì),讀請(qǐng)求較少。PheonixKVTest 模擬這一業(yè)務(wù)產(chǎn)生的元數(shù)據(jù)流量,但是也可以自行定義讀寫(xiě)比例,以及讀寫(xiě)鍵值對(duì)的大小和概率分布等。參考MemC3[9],使用不同讀寫(xiě)比例的業(yè)務(wù)流量來(lái)測(cè)試PheonixLSM 在不同流量模型下的性能表現(xiàn)。
本地引擎測(cè)試。使用 db_bench 的隨機(jī)讀寫(xiě)模式,對(duì)比 PheonixLSM 和 RocksDB 的讀寫(xiě)時(shí)延和尾時(shí)延(99 分位時(shí)延)。每輪實(shí)驗(yàn)使用 16 線程,共下發(fā) 1 000 萬(wàn)條隨機(jī)讀寫(xiě)請(qǐng)求。請(qǐng)求的key 和 value 為 128 字節(jié)的字符串,key 的選擇符合平均分布。調(diào)整讀寫(xiě)請(qǐng)求的比例,圖 8 是不同本地引擎的讀寫(xiě)時(shí)延對(duì)比結(jié)果。由圖 8 可知,PheonixLSM 和關(guān)掉 WAL 的 RocksDB 各項(xiàng)時(shí)延和尾時(shí)延差異均在 3% 之內(nèi),說(shuō)明 PheonixLSM的改造并沒(méi)有帶來(lái)性能損耗。當(dāng)讀寫(xiě)時(shí)延不同時(shí),與 RocksDB 相比,PheonixLSM 的寫(xiě)時(shí)延降低 94.1%~95.2%,說(shuō)明關(guān)閉 WAL 能帶來(lái)較大的性能提升。
圖8 不同本地引擎的讀寫(xiě)時(shí)延(平均時(shí)延和99 分位時(shí)延)對(duì)比Fig. 8 Read/write latency (average and 99-percentile)comparison of local engines
雙寫(xiě)消除。本文考察雙寫(xiě)消除為 PheonixKV帶來(lái)的性能提升。本實(shí)驗(yàn)使用 1/4/16/64 的并發(fā)數(shù),分別向 PheonixKV 集群插入 1 000 萬(wàn)條 key和 value,其均為 128 字節(jié)的隨機(jī)鍵值對(duì)。圖 9為使用 RocksDB 和 PheonixLSM 作底層引擎時(shí),PheonixKV 的吞吐對(duì)比結(jié)果。由圖 9 可知,當(dāng)并發(fā)數(shù)不同時(shí),與 RocksDB 相比,PheonixLSM的吞吐提升 32.0%~90.5%,其中,當(dāng)并發(fā)數(shù)為16 時(shí),吞吐提升最大。增加并發(fā)數(shù),RocksDB和 PheonixLSM 的單位計(jì)算資源吞吐均出現(xiàn)下降的情況,這是由于 CPU 需要處理更多的線程調(diào)度工作。在不同并發(fā)數(shù)下,PheonixLSM 能帶來(lái)8.0%~21.7% 的單位計(jì)算資源吞吐提升,且在并發(fā)數(shù)為 64 時(shí)的吞吐提升最大。
圖9 使用 RocksDB 和 PheonixLSM 作底層引擎時(shí)PheonixKV 的吞吐對(duì)比Fig. 9 Throughput comparison of PheonixKV with RocksDB and PheonixLSM, respectively
將并發(fā)數(shù)固定為 64,以請(qǐng)求的讀寫(xiě)比例為自變量,對(duì)比不同讀寫(xiě)比例下 PheonixKV 使用兩種底層引擎的性能。向 PheonixKV 下發(fā) 1 000 萬(wàn)條請(qǐng)求,吞吐和讀寫(xiě)時(shí)延(包括平均時(shí)延和 99 分位時(shí)延)的對(duì)比結(jié)果如圖 10 所示。對(duì)于同一種引擎,讀寫(xiě)比對(duì)于讀寫(xiě)時(shí)延影響較?。划?dāng)使用不同引擎時(shí),讀時(shí)延差異較小,均在 8% 以?xún)?nèi)。當(dāng)使用 PheonixLSM 時(shí),PheonixKV 在不同讀寫(xiě)比例下的平均寫(xiě)時(shí)延和 99 分位寫(xiě)時(shí)延分別降低 31.3%~35.5% 和 28.0%~37.8%。由圖 10 所示,PheonixLSM 將吞吐提升了 26.5%~50.3%。由于 PheonixLSM 主要改善寫(xiě)性能,當(dāng)讀寫(xiě)比為2∶8 時(shí),寫(xiě)請(qǐng)求占比最大,吞吐提升最多。
圖10 不同讀寫(xiě)比業(yè)務(wù)流量下的吞吐和讀寫(xiě)時(shí)延(平均時(shí)延和 99 分位時(shí)延)對(duì)比Fig. 10 Throughput and latency (average and 99-percentile) comparison of diあerent read/write ratio
本文驗(yàn)證 PheonixLSM 的狀態(tài)機(jī)實(shí)時(shí)刪除優(yōu)化,對(duì)空間放大問(wèn)題帶來(lái)的改善。首先在系統(tǒng)中寫(xiě)入 5 億鍵值對(duì),并結(jié)束一個(gè) KVAgent 進(jìn)程,當(dāng)繼續(xù)寫(xiě)入 1 000 萬(wàn)鍵值對(duì)后,重新開(kāi)啟該KVAgent 進(jìn)程。在修復(fù)過(guò)程中,以每秒一次的頻率對(duì)該 KVAgent 的磁盤(pán)空間使用情況進(jìn)行采樣。圖 11 為全量修復(fù)過(guò)程中的空間放大對(duì)比結(jié)果。當(dāng) RocksDB 作本地引擎時(shí),大量數(shù)據(jù)插入引發(fā)的合并操作,產(chǎn)生了較大的額外空間占用,即使在修復(fù)結(jié)束后,由于各層 SST 文件的分布還未穩(wěn)定,后臺(tái)仍在進(jìn)行合并操作,所以額外空間的占用還在增加。此外,后臺(tái)的合并任務(wù)也影響了正常的數(shù)據(jù)寫(xiě)入,導(dǎo)致修復(fù)時(shí)間變長(zhǎng)。以修復(fù)后的穩(wěn)態(tài)空間占用為基準(zhǔn),當(dāng) RocksDB 為本地引擎時(shí),空間放大最多為 65.6%;而當(dāng) PheonixLSM 為本地引擎時(shí),空間放大最多僅為 6.4%。由圖 11可知,PheonixLSM 將修復(fù)用時(shí)從 4 398 s 降低至1 217 s,節(jié)約了 72.3% 的修復(fù)用時(shí)。
圖11 全量修復(fù)過(guò)程中的空間放大對(duì)比Fig. 11 Comparison of spatial amplification during full-node repair
PheonixLSM 修改合并邏輯,潛在地增加SST 文件數(shù)目。圖 12 對(duì)比了隨著 PheonixKV 插入鍵值對(duì)數(shù)目的變化,不同底層引擎中 SST 文件數(shù)目及占用存儲(chǔ)空間的變化。當(dāng)鍵值對(duì)數(shù)目較少時(shí),PheonixLSM 導(dǎo)致 SST 文件數(shù)目增加較多;當(dāng)鍵值對(duì)為 1 000 萬(wàn)個(gè)時(shí),RocksDB僅有 20 個(gè) SST 文件,而 PheonixLSM 有 210個(gè)。然而,當(dāng)數(shù)據(jù)規(guī)模繼續(xù)擴(kuò)大時(shí),SST 文件的數(shù)目差異會(huì)減少,當(dāng)鍵值對(duì)為 10 億個(gè)時(shí),RocksDB 和 PheonixLSM 分別有 2 161 和 2 176個(gè) SST 文件,數(shù)目相差很小。綜合而言,PheonixLSM 帶來(lái)的 SST 文件數(shù)目增加,對(duì)于底層的文件系統(tǒng)來(lái)說(shuō),不會(huì)明顯增加處理壓力。當(dāng)鍵值對(duì)數(shù)目逐漸增加時(shí),與原生 RocksDB 相比,PheonixLSM 占用的存儲(chǔ)空間均沒(méi)有增加,請(qǐng)求處理的性能也沒(méi)有因此發(fā)生下降(見(jiàn)圖 8)。
圖12 RocksDB 和 PheonixLSM 的 SST 文件數(shù)目和空間占用對(duì)比Fig. 12 Number of SST files and space usage for RocksDB and PheonixLSM
作為存儲(chǔ)系統(tǒng)的核心組件,分布式鍵值存儲(chǔ)的性能和承載規(guī)模至關(guān)重要。然而,本地引擎并沒(méi)有很好地適配分布式鍵值存儲(chǔ)的業(yè)務(wù)特征。本文提出了針對(duì)分布式業(yè)務(wù)優(yōu)化的底層引擎PheonixLSM,解決了一致性協(xié)議日志和本地引擎 WAL 雙寫(xiě)問(wèn)題,以及全量修復(fù)過(guò)程中的額外空間放大問(wèn)題。據(jù)相關(guān)調(diào)查表明,PheonixLSM是第一個(gè)針對(duì)分布式鍵值存儲(chǔ)業(yè)務(wù)改造的底層引擎③:使用谷歌學(xué)術(shù)于 2021 年 5 月 26 日檢索英文關(guān)鍵字“distributed key-value storage; spatial amplification; extra synchronization”以及中文關(guān)鍵字“分布式鍵值存儲(chǔ);空間放大;雙寫(xiě)”的檢索結(jié)果中,均沒(méi)有相關(guān)的工作。,其有效解決了分布式鍵值存儲(chǔ)的痛點(diǎn),能夠?qū)⑼掏绿嵘?90% 以上;還可將全量修復(fù)的空間放大由 65.6% 降低至 6.4%,效果明顯;此外,還有效提升了分布式鍵值存儲(chǔ)的業(yè)務(wù)和修復(fù)性能,以及承載規(guī)模。在后續(xù)的工作中,還將進(jìn)一步結(jié)合分布式框架的業(yè)務(wù)模型,針對(duì)性?xún)?yōu)化底層引擎,從引入新型索引數(shù)據(jù)結(jié)構(gòu)、底層文件組織,以及發(fā)揮新型硬件特征等角度,進(jìn)一步提升分布式鍵值存儲(chǔ)的性能和承載規(guī)模。
分布式鍵值存儲(chǔ)的性能和承載規(guī)模,取決于底層引擎的能力,以及上層分布式路由模塊分發(fā)流量、均衡負(fù)載和存儲(chǔ)的能力。本文重點(diǎn)關(guān)注前者,后續(xù)基于 PheonixKV 的工作中,如何確保性能隨集群規(guī)模擴(kuò)大線性提升,各底層引擎性能均能得到發(fā)揮也將是重點(diǎn)研究方向。
本文描述了 PheonixLSM 的設(shè)計(jì)與實(shí)現(xiàn)。PheonixLSM 是一個(gè)基于 LSM 樹(shù)的本地鍵值引擎,面向分布式鍵值存儲(chǔ),進(jìn)行了針對(duì)性的優(yōu)化。PheonixLSM 通過(guò)改造 LSM 樹(shù)的增刪改和回刷流程以及 SST 文件的組織形式,配合上層分布式邏輯,解決了分布式鍵值存儲(chǔ)系統(tǒng)中一致性協(xié)議的雙寫(xiě)引發(fā)的性能問(wèn)題,以及全量修復(fù)時(shí)的額外空間放大問(wèn)題。本文在 RocksDB 的源代碼上進(jìn)行改造實(shí)現(xiàn)了 PheonixLSM,并在三主機(jī)的分布式集群上進(jìn)行了實(shí)驗(yàn)。實(shí)驗(yàn)結(jié)果證明,PheonixLSM帶來(lái)了性能改進(jìn),以及全量修復(fù)過(guò)程中空間放大問(wèn)題的有效消除。與原生 RocksDB 的分布式鍵值存儲(chǔ)相比,PheonixLSM 的分布式鍵值存儲(chǔ),吞吐提升 90% 以上,單位計(jì)算資源吞吐提升20% 以上。全量修復(fù)過(guò)程中的空間放大由 65.6%下降至 6.4%,并減少了 72.3% 的修復(fù)時(shí)間。