您好,登錄后才能下訂單哦!
UFS (UCloud File System) 是一款 UCloud 自主研發(fā)的分布式文件存儲產(chǎn)品,此前已推出容量型 UFS 版本。UFS 以其彈性在線擴容、穩(wěn)定可靠的特點,為眾多公有云、物理云、托管云用戶提供共享存儲方案,單文件系統(tǒng)存儲容量可達(dá)百 PB 級。
為了應(yīng)對 IO 性能要求很高的數(shù)據(jù)分析、AI 訓(xùn)練、高性能站點等場景,UFS 團(tuán)隊又推出了一款基于 NVMe SSD 介質(zhì)的性能型 UFS,以滿足高 IO 場景下業(yè)務(wù)對共享存儲的需求。性能型 UFS 的 4K 隨機寫的延遲能保持在 10ms 以下,4K 隨機讀延遲在 5ms 以下。
性能的提升不僅僅是因為存儲介質(zhì)的升級,更有架構(gòu)層面的改進(jìn),本文將從協(xié)議、索引、存儲設(shè)計等幾方面來詳細(xì)介紹性能型 UFS 升級改造的技術(shù)細(xì)節(jié)。
協(xié)議改進(jìn)
此前容量型 UFS 設(shè)計時支持的協(xié)議為 NFSv3,其設(shè)計理念是接口無狀態(tài),故障恢復(fù)的邏輯簡單。此外 NFSv3 在 Linux 和 Windows 上被廣泛支持,更易于跨平臺使用。但是 NFSv3 的設(shè)計缺點導(dǎo)致的高延遲在高 IO 場景下是不可接受的,所以在性能型 UFS 中,我們選擇僅支持性能更好、設(shè)計更先進(jìn)的 NFSv4 協(xié)議。
NFSv4 與 NFSv3 相比,更先進(jìn)的特性包括:支持有狀態(tài)的 lock 語義、多協(xié)議間的 compound 機制等。特別是 compound 機制,可以讓多次 NFS 協(xié)議交互在一個 RTT 中完成,很好地解決了 NFSv3 性能低效的問題。一次典型的 open for write 操作,在 NFSv3 和 NFSv4 上分別是這樣的:
cdn.xitu.io/2019/9/4/16cfae3a9aa57527?w=502&h=286&f=jpeg&s=15141">
可以看到,在關(guān)鍵的 IO 部分,NFSv4 比 NFSv3 節(jié)省一半的交互次數(shù),可以顯著降低 IO 延遲。除了協(xié)議以外,性能型 UFS 的核心由業(yè)務(wù)索引和底層存儲兩部分組成,由于底層 IO 性能的提升,這兩部分都需要進(jìn)行深度改造以適應(yīng)這種結(jié)構(gòu)性的改變。下面我們將分別介紹這兩部分的改造細(xì)節(jié)。
業(yè)務(wù)索引
索引服務(wù)是分布式文件系統(tǒng)的核心功能之一。相比對象存儲等其它存儲服務(wù),文件存儲的索引需要提供更為復(fù)雜的語義,所以會對性能產(chǎn)生更大影響。
索引服務(wù)的功能模塊設(shè)計是基于單機文件系統(tǒng)設(shè)計思路的一種『仿生』,分為兩大部分:
? 目錄索引: 實現(xiàn)樹狀層級目錄,記錄各個目錄下的文件和子目錄項
? 文件索引: 記錄文件元數(shù)據(jù),包含數(shù)據(jù)塊存儲信息和訪問權(quán)限等
索引服務(wù)各模塊的功能是明確的,主要解決兩個問題:
? 業(yè)務(wù)特性: 除了實現(xiàn)符合文件系統(tǒng)語義的各類操作外,還要保證索引數(shù)據(jù)的外部一致性,在各類并發(fā)場景下不對索引數(shù)據(jù)產(chǎn)生靜態(tài)修改從而產(chǎn)生數(shù)據(jù)丟失或損壞
? 分布式系統(tǒng)特性: 包括系統(tǒng)拓展性、可靠性等問題,使系統(tǒng)能夠應(yīng)對各類節(jié)點和數(shù)據(jù)故障,保證系統(tǒng)對外的高可用性和系統(tǒng)彈性等
雖然功能有區(qū)別,目錄索引和文件索引在架構(gòu)上是類似的,所以我們下面只介紹文件索引 (FileIdx) 架構(gòu)。在以上的目標(biāo)指導(dǎo)下,最終 FileIdx 采用無狀態(tài)設(shè)計,依靠各索引節(jié)點和 master 之間的租約(Lease)機制來做節(jié)點管理,實現(xiàn)其容災(zāi)和彈性架構(gòu)。
租約機制和悲觀鎖
master 模塊負(fù)責(zé)維護(hù)一張路由表,路由表可以理解成一個由虛節(jié)點組成的一致性哈希環(huán),每個 FileIdx 實例負(fù)責(zé)其中的部分虛節(jié)點,master 通過心跳和各個實例節(jié)點進(jìn)行存活性探測,并用租約機制告知 FileIdx 實例和各個 NFSServer 具體的虛節(jié)點由誰負(fù)責(zé)處理。如果某個 FileIdx 實例發(fā)生故障,master 只需要在當(dāng)前租約失效后將該節(jié)點負(fù)責(zé)的虛節(jié)點分配給其他實例處理即可。
當(dāng) NFSServer 需要向文件服務(wù)請求具體操作 (比如請求分配 IO 塊) 時,會對請求涉及的文件句柄做哈希操作確認(rèn)負(fù)責(zé)該文件的虛節(jié)點由哪個 FileIdx 處理,將請求發(fā)至該節(jié)點。每個節(jié)點上為每個文件句柄維持一個處理隊列,隊列按照 FIFO 方式進(jìn)行執(zhí)行。本質(zhì)上這構(gòu)成了一個悲觀鎖,當(dāng)一個文件的操作遇到較多并發(fā)時,我們保證在特定節(jié)點和特定隊列上的排隊,使得并發(fā)修改導(dǎo)致的沖突降到最低。
更新保護(hù)
盡管租約機制一定程度上保證了文件索引操作的并發(fā)安全性,但是在極端情況下租約也不能保持并發(fā)操作的絕對互斥及有序。所以我們在索引數(shù)據(jù)庫上基于 CAS 和 MVCC 技術(shù)對索引進(jìn)行更新保護(hù),確保索引數(shù)據(jù)不會因為并發(fā)更新而喪失外部一致性。
IO 塊分配優(yōu)化
在性能型 UFS 中,底層存儲的 IO 延遲大幅降低帶來了更高的 IOPS 和吞吐,也對索引模塊特別是 IO 塊的分配性能提出了挑戰(zhàn)。頻繁地申請 IO 塊導(dǎo)致索引在整個 IO 鏈路上貢獻(xiàn)的延遲比例更高,對性能帶來了損害。一方面我們對索引進(jìn)行了讀寫分離改造,引入緩存和批量更新機制,提升單次 IO 塊分配的性能。
同時,我們增大了 IO 塊的大小,更大的 IO 數(shù)據(jù)塊降低了分配和獲取數(shù)據(jù)塊的頻率,將分配開銷進(jìn)行均攤。后續(xù)我們還將對索引關(guān)鍵操作進(jìn)行異步化改造,讓 IO 塊的分配從 IO 關(guān)鍵路徑上移除,最大程度降低索引操作對 IO 性能的影響。
底層存儲
設(shè)計理念
存儲功能是一個存儲系統(tǒng)的重中之重,它的設(shè)計實現(xiàn)關(guān)系到系統(tǒng)最終的性能、穩(wěn)定性等。通過對 UFS 在數(shù)據(jù)存儲、數(shù)據(jù)操作等方面的需求分析,我們認(rèn)為底層存儲 (命名為 nebula) 應(yīng)該滿足如下的要求:?簡單:簡單可理解的系統(tǒng)有利于后期維護(hù)?可靠:必須保證高可用性、高可靠性等分布式要求?拓展方便:包括處理集群擴容、數(shù)據(jù)均衡等操作?支持隨機 IO?充分利用高性能存儲介質(zhì)
Nebula: append-only 和中心化索引
基于以上目標(biāo),我們將底層存儲系統(tǒng) nebula 設(shè)計為基于 append-only 的存儲系統(tǒng) (immutable storage)。面向追加寫的方式使得存儲邏輯會更簡單,在多副本數(shù)據(jù)的同步上可以有效降低數(shù)據(jù)一致性的容錯復(fù)雜度。更關(guān)鍵的是,由于追加寫本質(zhì)上是一個 log-based 的記錄方式,整個 IO 的歷史記錄都被保存,在此之上實現(xiàn)數(shù)據(jù)快照和數(shù)據(jù)回滾會很方便,在出現(xiàn)數(shù)據(jù)故障時,更容易做數(shù)據(jù)恢復(fù)操作。
在現(xiàn)有的存儲系統(tǒng)設(shè)計中,按照數(shù)據(jù)尋址的方式可以分為去中心化和中心化索引兩種,這兩者的典型代表系統(tǒng)是 Ceph 和 Google File System。去中心化的設(shè)計消除了系統(tǒng)在索引側(cè)的故障風(fēng)險點,并且降低了數(shù)據(jù)尋址的開銷。但是增加了數(shù)據(jù)遷移、數(shù)據(jù)分布管理等功能的復(fù)雜度。出于系統(tǒng)簡單可靠的設(shè)計目標(biāo),我們最終選擇了中心化索引的設(shè)計方式,中心化索引使集群擴容等拓展性操作變得更容易。
數(shù)據(jù)塊管理:extent-based 理念
中心化索引面臨的性能瓶頸主要在數(shù)據(jù)塊的分配上,我們可以類比一下單機文件系統(tǒng)在這方面的設(shè)計思路。早期文件系統(tǒng)的 inode 對數(shù)據(jù)塊的管理是 block-based,每次 IO 都會申請 block 進(jìn)行寫入,典型的 block 大小為 4KB,這就導(dǎo)致兩個問題:1、4KB 的數(shù)據(jù)塊比較小,對于大片的寫入需要頻繁進(jìn)行數(shù)據(jù)塊申請操作,不利于發(fā)揮順序 IO 的優(yōu)勢。2、inode 在基于 block 的方式下表示大文件時需要更大的元數(shù)據(jù)空間,能表示的文件大小也受到限制。
在 Ext4/XFS 等更先進(jìn)的文件系統(tǒng)設(shè)計中,inode 被設(shè)計成使用 extent-based 的方式來實現(xiàn),每個 extent 不再被固定的 block 大小限制,相反它可以用來表示一段不定長的磁盤空間,如下圖所示:
顯然地,在這種方式下,IO 能夠得到更大更連續(xù)的磁盤空間,有助于發(fā)揮磁盤的順序?qū)懩芰?,并且有效降低了分?block 的開銷,IO 的性能也得到了提升,更關(guān)鍵的是,它可以和追加寫存儲系統(tǒng)非常好地結(jié)合起來。我們看到,不僅僅在單機文件系統(tǒng)中,在 Google File System、Windows Azure Storage 等分布式系統(tǒng)中也可以看到 extent-based 的設(shè)計思想。我們的 nebula 也基于這一理念進(jìn)行了模型設(shè)計。
存儲架構(gòu)
Stream 數(shù)據(jù)流
在 nebula 系統(tǒng)中存儲的數(shù)據(jù)按照 stream 為單位進(jìn)行組織,每個 stream 稱為一個數(shù)據(jù)流,它由一個或多個 extent 組成,每次針對該 stream 的寫入操作以 block 為單位在最后一個 extent 上進(jìn)行追加寫,并且只有最后一個 extent 允許寫入,每個 block 的長度不定,可由上層業(yè)務(wù)結(jié)合場景決定。而每個 extent 在邏輯上構(gòu)成一個副本組,副本組在物理上按照冗余策略在各存儲節(jié)點維持多副本,stream 的 IO 模型如下:
streamsvr 和 extentsvr
基于這個模型,存儲系統(tǒng)被分為兩大主要模塊:?streamsvr:負(fù)責(zé)維護(hù)各個 stream 和 extent 之間的映射關(guān)系以及 extent 的副本位置等元數(shù)據(jù),并且對數(shù)據(jù)調(diào)度、均衡等做管控?extentsvr:每塊磁盤對應(yīng)一個 extentsvr 服務(wù)進(jìn)程,負(fù)責(zé)存儲實際的 extent 數(shù)據(jù)存儲,處理前端過來的 IO 請求,執(zhí)行 extent 數(shù)據(jù)的多副本操作和修復(fù)等
在存儲集群中,所有磁盤通過 extentsvr 表現(xiàn)為一個大的存儲池,當(dāng)一個 extent 被請求創(chuàng)建時,streamsvr 根據(jù)它對集群管理的全局視角,從負(fù)載和數(shù)據(jù)均衡等多個角度選取其多副本所在的 extentsvr,之后 IO 請求由客戶端直接和 extentsvr 節(jié)點進(jìn)行交互完成。在某個存儲節(jié)點發(fā)生故障時,客戶端只需要 seal 掉當(dāng)前在寫入的 extent,創(chuàng)建一個新的 extent 進(jìn)行寫入即可,節(jié)點容災(zāi)在一次 streamsvr 的 rpc 調(diào)用的延遲級別即可完成,這也是基于追加寫方式實現(xiàn)帶來的系統(tǒng)簡潔性的體現(xiàn)。
由此,存儲層各模塊的架構(gòu)圖如下:
至此,數(shù)據(jù)已經(jīng)可以通過各模塊的協(xié)作寫入到 extentsvr 節(jié)點,至于數(shù)據(jù)在具體磁盤上的存儲布局,這是單盤存儲引擎的工作。
單盤存儲引擎
前面的存儲架構(gòu)講述了整個 IO 在存儲層的功能分工,為了保證性能型 UFS 的高性能,我們在單盤存儲引擎上做了一些優(yōu)化。
線程模型優(yōu)化
存儲介質(zhì)性能的大幅提升對存儲引擎的設(shè)計帶來了全新的需求。在容量型 UFS 的 SATA 介質(zhì)上,磁盤的吞吐較低延遲較高,一臺存儲機器的整體吞吐受限于磁盤的吞吐,一個單線程 / 單進(jìn)程的服務(wù)就可以讓磁盤吞吐打滿。隨著存儲介質(zhì)處理能力的提升,IO 的系統(tǒng)瓶頸逐漸從磁盤往處理器和網(wǎng)絡(luò)帶寬方面轉(zhuǎn)移。
在 NVMe SSD 介質(zhì)上由于其多隊列的并行設(shè)計,單線程模型已經(jīng)無法發(fā)揮磁盤性能優(yōu)勢,系統(tǒng)中斷、網(wǎng)卡中斷將成為 CPU 新的瓶頸點,我們需要將服務(wù)模型轉(zhuǎn)換到多線程方式,以此充分發(fā)揮底層介質(zhì)多隊列的并行處理能力。為此我們重寫了編程框架,新框架采用 one loop per thread 的線程模型,并通過 Lock-free 等設(shè)計來最大化挖掘磁盤性能。
block 尋址
讓我們思考一個問題,當(dāng)客戶端寫入了一片數(shù)據(jù) block 之后,讀取時如何找到 block 數(shù)據(jù)位置?一種方式是這樣的,給每個 block 分配一個唯一的 blockid,通過兩級索引轉(zhuǎn)換進(jìn)行尋址:
?第一級:查詢 streamsvr 定位到 blockid 和 extent 的關(guān)系
?第二級:找到 extent 所在的副本,查詢 blockid 在 extent 內(nèi)的偏移,然后讀取數(shù)據(jù)
這種實現(xiàn)方式面臨兩個問題,(1)第一級的轉(zhuǎn)換需求導(dǎo)致 streamsvr 需要記錄的索引量很大,而且查詢交互會導(dǎo)致 IO 延遲升高降低性能。(2)第二級轉(zhuǎn)換以 Facebook Haystack 系統(tǒng)為典型代表,每個 extent 在文件系統(tǒng)上用一個獨立文件表示,extentsvr 記錄每個 block 在 extent 文件中的偏移,并在啟動時將全部索引信息加載在內(nèi)存里,以提升查詢開銷,查詢這個索引在多線程框架下必然因為互斥機制導(dǎo)致查詢延遲,因此在高性能場景下也是不可取的。而且基于文件系統(tǒng)的操作讓整個存儲棧的 IO 路徑過長,性能調(diào)優(yōu)不可控,也不利于 SPDK 技術(shù)的引入。
為避免上述不利因素,我們的存儲引擎是基于裸盤設(shè)計的,一塊物理磁盤將被分為幾個核心部分:
?superblock: 超級塊,記錄了 segment 大小,segment 起始位置以及其他索引塊位置等
?segment: 數(shù)據(jù)分配單位,整個磁盤除了超級塊以外,其他區(qū)域全部都是 segment 區(qū)域,每個 segment 是定長的 (默認(rèn)為 128MB),每個 extent 都由一個或多個 segment 組成
?extent index / segment meta region: extent/segment 索引區(qū)域,記錄了每個 extent 對應(yīng)的 segment 列表,以及 segment 的狀態(tài) (是否可用) 等信息
基于這個設(shè)計,我們可以將 block 的尋址優(yōu)化為無須查詢的純計算方式。當(dāng)寫完一個 block 之后,將返回該 block 在整個 stream 中的偏移。客戶端請求該 block 時只需要將此偏移傳遞給 extentsvr,由于 segment 是定長的,extentsvr 很容易就計算出該偏移在磁盤上的位置,從而定位到數(shù)據(jù)進(jìn)行讀取,這樣就消除了數(shù)據(jù)尋址時的查詢開銷。
隨機 IO 支持:FileLayer 中間層
我們之前出于簡單可靠的理念將存儲系統(tǒng)設(shè)計為 append-only,但是又由于文件存儲的業(yè)務(wù)特性,需要支持覆蓋寫這類隨機 IO 場景。
因此我們引入了一個中間層 FileLayer 來支持隨機 IO,在一個追加寫的引擎上實現(xiàn)隨機寫,該思路借鑒于 Log-Structured File System 的實現(xiàn)。LevelDB 使用的 LSM-Tree 和 SSD 控制器里的 FTL 都有類似的實現(xiàn),被覆蓋的數(shù)據(jù)只在索引層面進(jìn)行間接修改,而不是直接對數(shù)據(jù)做覆蓋寫或者是 COW (copy-on-write),這樣既可以用較小的代價實現(xiàn)覆蓋寫,又可以保留底層追加寫的簡單性。
FileLayer 中發(fā)生 IO 操作的單元稱為 dataunit,每次讀寫操作涉及的 block 都在某個 dataunit 上進(jìn)行處理,dataunit 的邏輯組成由如下幾個部分:
dataunit 由多個 segment 組成 (注意這和底層存儲的 segment 不是一個概念),因為基于 LSM-Tree 的設(shè)計最終需要做 compaction, 多 segment 的劃分類似于 LevelDB 中的多層 sst 概念,最下層的 segment 是只讀的,只有最上層的 segment 允許寫入,這使得 compaction 操作可以更簡單可靠地進(jìn)行甚至回滾,而由于每次 compaction 涉及的數(shù)據(jù)域是確定的,也便于我們檢驗 compaction 操作的 invariant:回收前后數(shù)據(jù)域內(nèi)的有效數(shù)據(jù)必須是一樣的。
每個 segment 則由一個索引流和一個數(shù)據(jù)流組成,它們都存儲在底層存儲系統(tǒng) nebula 上,每次寫入 IO 需要做一次數(shù)據(jù)流的同步寫,而為了提升 IO 性能,索引流的寫入是異步的,并且維護(hù)一份純內(nèi)存索引提升查詢操作性能。為了做到這一點,每次寫入到數(shù)據(jù)流中的數(shù)據(jù)是自包含的,這意味著如果索引流缺失部分?jǐn)?shù)據(jù)甚至損壞,我們可以從數(shù)據(jù)流中完整構(gòu)建整個索引。
客戶端以文件為粒度寫入到 dataunit 中,dataunit 會給每個文件分配一個全局唯一的 fid,fid 作為數(shù)據(jù)句柄存儲到業(yè)務(wù)索引中 (FileIdx 的 block 句柄)。
dataunit 本身則由 fileserver 服務(wù)進(jìn)程負(fù)責(zé),每個 fileserver 可以有多個 dataunit,coordinator 根據(jù)各節(jié)點的負(fù)載在實例間進(jìn)行 dataunit 的調(diào)度和容災(zāi)。整個 FileLayer 的架構(gòu)如下:
至此,存儲系統(tǒng)已經(jīng)按照設(shè)計要求滿足了我們文件存儲的需求,下面我們來看一看各個模塊是如何一起協(xié)作來完成一次文件 IO 的。
The Big Picture:一次文件寫 IO 的全流程
從整體來說,一次文件寫 IO 的大致流程是這樣的:
①用戶在主機上發(fā)起 IO 操作會在內(nèi)核層被 nfs-client 在 VFS 層截獲 (僅以 Linux 系統(tǒng)下為例),通過被隔離的 VPC 網(wǎng)絡(luò)發(fā)往 UFS 服務(wù)的接入層。
②接入層通過對 NFS 協(xié)議的解析和轉(zhuǎn)義,將這個操作分解為索引和數(shù)據(jù)操作。
③經(jīng)過索引模塊將這個操作在文件內(nèi)涉及的 IO 范圍轉(zhuǎn)化為由多個 file system block (固定大小,默認(rèn) 4MB) 表示的 IO 范圍。
④NFSServer 拿到需要操作的 block 的句柄 (bid) 后去請求 FileLayer 進(jìn)行 IO 操作 (每個 bid 在 FileLayer 中代表一個文件)。
請求會被 NFSServer 發(fā)往負(fù)責(zé)處理該 bid 對應(yīng)的文件的 fileserver 上,fileserver 獲取該文件所在的 dataunit 編號 (此編號被編碼在 bid 中) 后,直接往該 dataunit 當(dāng)前的數(shù)據(jù)流 (stream) 中進(jìn)行追加寫,完成后更新索引,將新寫入的數(shù)據(jù)的位置記錄下來,本次 IO 即告完成,可以向 NFSServer 返回 并回應(yīng)了。類似地,當(dāng) fileserver 產(chǎn)生的追加寫 IO 抵達(dá)其所屬的 extentsvr 的時候,extentsvr 確定出該 stream 對應(yīng)的最后一個 extent 在磁盤上的位置,并執(zhí)行一次追加寫落地數(shù)據(jù),在完成多副本同步后返回。
至此,一次文件寫 IO 就完成了。
性能數(shù)據(jù)
經(jīng)過前述的設(shè)計和優(yōu)化,性能型 UFS 的實際性能數(shù)據(jù)如下:
總結(jié)
本文從 UFS 性能型產(chǎn)品的需求出發(fā),詳細(xì)介紹了基于高性能存儲介質(zhì)構(gòu)建分布式文件系統(tǒng)時,在協(xié)議、業(yè)務(wù)架構(gòu)、存儲引擎等多方面的設(shè)計考慮和優(yōu)化,并最終將這些優(yōu)化落實到產(chǎn)品中去。性能型 UFS 的上線豐富了產(chǎn)品種類,各類對 IO 延遲要求更高的大數(shù)據(jù)分析、AI 訓(xùn)練等業(yè)務(wù)場景將得到更好的助力。
后續(xù)我們將在多方面繼續(xù)提升 UFS 的使用體驗,產(chǎn)品上會支持 SMB 協(xié)議,提升 Windows 主機使用文件存儲的性能;底層存儲會引入 SPDK、RDMA 等技術(shù),并結(jié)合其它更高性能的存儲介質(zhì);在冷存數(shù)據(jù)場景下引入 Erasure Coding 等技術(shù);使用戶能夠享受到更先進(jìn)的技術(shù)帶來的性能和價格紅利。
產(chǎn)品最新優(yōu)惠:性能型 UFS 原價 1.0 元 /GB/ 月,現(xiàn)在福建可用區(qū)優(yōu)惠價 0.6 元 /GB/ 月,國內(nèi)其他可用區(qū) 0.8 元 /GB/ 月,歡迎聯(lián)系客戶經(jīng)理申請體驗!
如您有本篇文章相關(guān)問題,歡迎添加作者咨詢。WeChat ID:cheneydeng
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。