大規(guī)模塊存儲 EC 系統(tǒng)構(gòu)建
本文整理自 2023 年 7 月 DataFunSummit 2023 數(shù)據(jù)基礎(chǔ)架構(gòu)峰會——大規(guī)模存儲架構(gòu)分論壇的同名主題分享。
非常歡迎大家的到來,今天由我來分享百度智能云塊存儲 EC 系統(tǒng)的構(gòu)建。塊存儲系統(tǒng)在百度智能云的產(chǎn)品名叫 CDS,底層 EC 系統(tǒng)由 Aries 承擔(dān)。
關(guān)于 Aries 的詳細(xì)介紹,可以參考文末「傳送門」的第一篇文章。
今天主要介紹的內(nèi)容如下,首先會比較一下各種容錯方式,介紹一下我們選擇 EC 容錯方式的必然性;然后給大家介紹一下在塊存儲產(chǎn)品下構(gòu)建 EC 引擎的挑戰(zhàn),并逐步展開對這些挑戰(zhàn)進(jìn)行分析和解決的方法;最后,我們介紹一下基于這個解決方案的一些優(yōu)化。
1. 數(shù)據(jù)容錯方式比較
首先介紹一下常見的數(shù)據(jù)容錯方式。
數(shù)據(jù)容錯在單機(jī)和分布式系統(tǒng)下,有著不同的選擇。
單機(jī)情況下,比較直接的方式是選用 RAID 卡。在 BIOS 中配置,一般支持 RAID5 就夠了。如果沒有 RAID 卡,也可以用軟 RAID,創(chuàng)建帶有 RAID 功能的邏輯卷。
分布式的情況,比較直接的方式是采用多副本的形式,將數(shù)據(jù)復(fù)制成多份,存在不同的機(jī)器。實際上,最好將每份數(shù)據(jù)保存到不同的交換機(jī)下。另外一種方式是采用分布式糾刪碼的方式。這種方式其實就是分布式的 RAID。只不過,單機(jī)用奇偶校驗的 RAID5 基本可以保證數(shù)據(jù)安全,而分布式系統(tǒng)中,由于磁盤規(guī)模龐大,糾刪碼的復(fù)雜度要高一些。
圖片
這里介紹一下分布式容錯方式的實現(xiàn)。多副本方式容錯,每個副本的數(shù)據(jù)相同,所以,一般采用分布式的一致性協(xié)議對數(shù)據(jù)進(jìn)行同步,主流的協(xié)議為 Paxos 和 Raft。有的系統(tǒng)也會自研一些分發(fā)寫的協(xié)議。最終目的是保證多份數(shù)據(jù)相同。多副本情況下,假設(shè)是 N 副本,則最多允許 N-1 份數(shù)據(jù)損壞。
糾刪碼則是將用戶的原始數(shù)據(jù)進(jìn)行切分,形成 K 個大小相等的分片,然后對這些分片進(jìn)行編碼,形成 M 個校驗分片。校驗分片的大小和數(shù)據(jù)分片相同。K+M 個分片會被分布在不同的機(jī)器上。一般情況下,糾刪碼允許最多 M 個分片數(shù)據(jù)損壞。最常用的糾刪碼是 Reed-Solomon 編碼(RS 碼);
圖片
從成本考慮,3 副本將數(shù)據(jù)存儲 3 份,因此是 3 倍的存儲成本。而糾刪碼,是 K+M 的形式,K 份的數(shù)據(jù),編碼形成 M 份校驗。通常情況下,M 比 K 要小。因此存儲成本一般為 1.x 倍。
但是,糾刪碼也有自己缺點(diǎn)。多副本將數(shù)據(jù)無修改地復(fù)制到另外節(jié)點(diǎn),不需要計算參與,數(shù)據(jù)恢復(fù)則是將數(shù)據(jù)重新復(fù)制一遍,方法比較簡單。而糾刪碼則涉及到編碼和解碼,除了計算以外,編碼和解碼同樣會帶來額外的 I/O 開銷。
現(xiàn)代 CPU 已經(jīng)支持 RS 編碼的硬件加速,能夠提升編碼/解碼速度,極大減少計算壓力。而 I/O 放大,則是我們重點(diǎn)要解決的問題。
磁盤通常具有 1%~2% 的年化故障率。由于分布式系統(tǒng)規(guī)模都比較大,大的集群都會有千臺機(jī)器,萬塊磁盤的規(guī)模,一定會同時出現(xiàn)多塊磁盤同時故障。因此,一般分布式系統(tǒng)都采用 2 個以上的備份或者校驗。一般采用 3 副本或者 RS 編碼才能保證數(shù)據(jù)的可靠性?;谀壳暗募阂?guī)模和成本,糾刪碼是必然的選擇。
圖片
2. 大規(guī)模塊存儲 EC 的技術(shù)挑戰(zhàn)
既然選擇了糾刪碼,下面那必須解決 EC 系統(tǒng)中面臨的各種問題。
系統(tǒng)面臨的挑戰(zhàn)主要來自幾個方面。一個是產(chǎn)品訪問特性,塊存儲存儲的是動態(tài)數(shù)據(jù),用戶會隨時對數(shù)據(jù)進(jìn)行修改。而 EC 修改代價高,原地修改需要引入額外計算和 I/O 放大。
另外就是用戶下發(fā)給磁盤的數(shù)據(jù)大小不一,而小寫不適合 EC。如何解決小 I/O 的 EC,是另外一個問題。
應(yīng)用場景上,用戶對大小寫的要求是不一樣的。因此,我們的設(shè)計需要一個合理的系統(tǒng)開銷,減少資源占用,使得用戶有比較好的 I/O 表現(xiàn)。
圖片
對比一下對象存儲。它對外的接口是 put、get、delete。寫入時,將一個對象的整體數(shù)據(jù)整體寫入和整體刪除,不涉及到重新編碼的問題。因此,除了寫入時產(chǎn)生的校驗數(shù)據(jù)需要保存,沒有其他寫放大問題。
圖片
塊存儲,主要接口是讀寫和刪除。與對象存儲不同,這里的寫絕大部分是對原有數(shù)據(jù)的修改。
對于部分?jǐn)?shù)據(jù)修改,如果重新計算校驗,需要將剩余數(shù)據(jù)從其余節(jié)點(diǎn)讀到內(nèi)存中,重新計算校驗值,然后將校驗再次寫回。這里涉及到了「讀-修改-寫」,I/O 放大比較嚴(yán)重。
圖片
這里是線上 I/O 次數(shù)統(tǒng)計,小 I/O 的次數(shù)遠(yuǎn)遠(yuǎn)多于大 I/O。塊存儲 CDS 中,4K 大小的 I/O 占據(jù)了半數(shù)以上的寫次數(shù)。但是小 I/O 不太適合 EC。
舉個例子:我們?nèi)绻捎?K 為 4,M 為 2 的編碼,需要將分片切成 1K 大小,而一般情況下,文件系統(tǒng)對于 4K 倍數(shù)的 I/O 支持比較友好,1K 的 I/O size,相對來說,不是很合理的 I/O size。如果 K 值更大,會產(chǎn)生更細(xì)碎的分片。我們需要解決這些小 I/O 的 EC。
圖片
現(xiàn)代軟件已經(jīng)對磁盤訪問有比較多的優(yōu)化。當(dāng)程序追求吞吐時會下發(fā)大 I/O,減少磁盤尋道時間。當(dāng)程序?qū)ρ訒r有需求時,通常會下發(fā)盡量小的 I/O,減少不必要的數(shù)據(jù)對 I/O 帶寬的占用。
因此,總體看來,對于小 I/O用戶需要的是小的延時,對于用戶大的 I/O 用戶需要的是高的吞吐。
硬件的物理帶寬是有限的,提供高性能的存儲引擎,系統(tǒng)本身占用的資源應(yīng)該盡量小。對于存儲引擎來說,主要就是寫放大問題。
圖片
3. 百度滄海的實現(xiàn)方案
針對以上問題,我們看一下百度滄海的解決方案。
這里我們重新看一下修改,I/O 放大的主要原因是需要對原有存量數(shù)據(jù)進(jìn)行修改操作,如果不做特殊優(yōu)化,這些操作需要將原有數(shù)據(jù)讀出來,用于計算新的校驗。
CDS 的選擇是構(gòu)建一個索引層,索引指向 EC 后的數(shù)據(jù),數(shù)據(jù)的修改不在原地進(jìn)行。
這里給了個例子,用戶第一次寫的數(shù)據(jù),EC 并且存儲后,建立了一個索引指向這塊數(shù)據(jù)。后續(xù)在中間的修改將作為一個新數(shù)據(jù)進(jìn)行 EC 并且存儲。然后構(gòu)建新的索引指向新的數(shù)據(jù),之前的索引分裂成 2 部分。
圖片
這樣做后,我們實際上建立了一個基于 EC 數(shù)據(jù)的 Append 引擎。EC 后的數(shù)據(jù),對應(yīng)的就是 Append 引擎中的 segment。所有的修改采用追加寫的形式,等同于 append 引擎的單路追加寫。
實際上,CDS 并未從頭開始設(shè)計一個 EC 系統(tǒng),而是采用了公司內(nèi)成熟的 EC 系統(tǒng) Aries 作為底層儲存介質(zhì),Aries 是百度滄海提供的特別優(yōu)秀的 EC 系統(tǒng)和數(shù)據(jù)底座。寫入 Aries 的數(shù)據(jù)將作為一個 slice 存儲,而一個 slice 可以對應(yīng)到邏輯層的一個 segment。
圖片
我們前面提到了需要處理用戶小寫 EC 的問題。可以采用的一個方案是建立一個三副本的存儲層,用來緩存用戶 I/O。當(dāng)用戶寫滿一定規(guī)模的數(shù)據(jù)時(比如:1GB),將這些數(shù)據(jù) EC 后進(jìn)行存儲。
這樣的好處是所有寫數(shù)據(jù)混在一起進(jìn)行存儲,分片的切分可以根據(jù) EC 規(guī)模進(jìn)行選擇,可以做到分片對 I/O 友好。其中,EC 層基本可以假設(shè)分片是固定大小的。
圖片
但是,這么做的缺點(diǎn)也很明顯。數(shù)據(jù)會被先寫到 3 副本層,再寫到 EC 層。一定會有多于 4 倍的 I/O 放大。我們也統(tǒng)計了線上數(shù)據(jù)的寫入量,數(shù)據(jù)量占據(jù)比較多的是大 I/O。這些大 I/O 對 EC 相對比較友好,可以采用直接 EC 的方式進(jìn)行。
圖片
百度滄海的方案是將大寫和小寫進(jìn)行分別處理。大寫直接進(jìn)行 EC,小寫采用 3 副本形式存儲。
這樣做的好處是,大寫的數(shù)據(jù)不經(jīng)過 3 副本層,規(guī)避了緩存帶來的絕大多數(shù) I/O 放大。3 副本主要存儲小 I/O,因為占比小,所以對成本的壓力增長不是很大,I/O 放大也不是很嚴(yán)重。
圖片
系統(tǒng)實現(xiàn)時,預(yù)留了 10% 作為 3 副本存儲空間。3 副本也采用 append 引擎進(jìn)行存儲。數(shù)據(jù) compaction 時,直接將數(shù)據(jù)存儲到 EC 層。
這種設(shè)計,當(dāng) 3 副本層空間緊張時,數(shù)據(jù)仍然會被進(jìn)行 EC 存儲,能夠在用戶都是小 I/O 的極端情況下,仍然有不錯的成本表現(xiàn)。
圖片
內(nèi)部交流時,經(jīng)常會被問到數(shù)據(jù)是否會從 EC 層轉(zhuǎn)移到 3 副本層。如果是同種介質(zhì),我們假設(shè)訪問延時沒有變化。因此,不將 3 副本層作為緩存層。
圖片
大 I/O 并不是固定大小,系統(tǒng)選擇將大 I/O 直接 EC 的情況下,對于底層 EC 的存儲引擎有新的要求。它必須能夠處理不同大小的分片。
設(shè)計難點(diǎn)是,釋放的空間如何被回收利用。圖中給了個例子,當(dāng)數(shù)據(jù)比空洞大時,無法將數(shù)據(jù)放入;當(dāng)數(shù)據(jù)比空洞小時,造成空間浪費(fèi)。因此,下層存儲應(yīng)該采用能夠很好適應(yīng)變長分片的引擎。
圖片
EC 存儲引擎層仍然采用 append 寫的方式。新數(shù)據(jù) append 寫,緊密排列在存儲系統(tǒng)的后端。這樣,新數(shù)據(jù)的空間分配變的簡單。
相對于原地寫,append 寫無論是對于 ssd 還是 hdd,性能都更好,這也為高性能存儲打下了基礎(chǔ)。
圖片
因此,總體架構(gòu)是一個雙層 append 架構(gòu)。第一層有一個邏輯的 append 引擎,每個 EC 數(shù)據(jù)對應(yīng)一個邏輯 segment。下層物理層存儲 EC 的分片,也采用 append 的方式,數(shù)據(jù)只進(jìn)行追加寫。
我們通過兩層架構(gòu)解決了修改放大,大小寫如何 EC 的問題。但是,仍然需要進(jìn)一步提高系統(tǒng)性能,提升用戶體驗。
圖片
目前采用 2 層 append 引擎的方式構(gòu)建系統(tǒng)。Append 的性能必然會對系統(tǒng)產(chǎn)生比較大的影響。存儲系統(tǒng),一般的瓶頸都是 I/O。Append 引擎天然存在寫放大,主要來源為 compaction。
由于系統(tǒng)總帶寬固定,如果 compaction 占用的帶寬過大,留給用戶使用的帶寬就會降低,影響用戶體驗。
Append 引擎的一個重要評價指標(biāo),就是 I/O 放大,即系統(tǒng)總的物理 I/O 除以用戶的 I/O。
圖片
要實現(xiàn)比較低的 I/O 放大,我們需要了解用戶數(shù)據(jù)的訪問特征。根據(jù)用戶數(shù)據(jù)的訪問特征,進(jìn)行有效優(yōu)化。
一般來說,用戶的數(shù)據(jù)訪問都存在熱點(diǎn)情況。即最近寫過的數(shù)據(jù),被再次寫的概率更大,也符合齊夫分布的特征。
齊夫分布,如公式所示,r 為訪問頻率的排名。C 和 ? 為常數(shù)。即排名越往后,訪問頻率越低。對這個公式同時取對數(shù)的情況下,是一個下降的直線。我們也對線上數(shù)據(jù)的寫頻率進(jìn)行了統(tǒng)計。除了長尾外,前半部分排名的數(shù)據(jù),基本符合齊夫分布。
如果按照訪問時間進(jìn)行統(tǒng)計,那么 1 天內(nèi)有寫的熱數(shù)據(jù),只占總數(shù)據(jù)的 5% 左右。
圖片
既然數(shù)據(jù)有冷熱,那么當(dāng)我們選擇 segment 進(jìn)行 compaction,就可以利用數(shù)據(jù)的這種訪問特點(diǎn)進(jìn)行。
一般的選擇方法是貪心算法,即選擇最空的 segment 進(jìn)行 compaction。如圖中的例子,在貪心算法的情況下,由于 segment B 的空洞率更高,會選擇 segment B 進(jìn)行 compaction。但是,由于 B 中的數(shù)據(jù)比較新,很有可能是熱數(shù)據(jù),則這些數(shù)據(jù)過很小的一段時間就可能被覆蓋寫。這次數(shù)據(jù)搬遷就顯得多余。
考慮到 segment A 中數(shù)據(jù)比較老。按照用戶訪問特點(diǎn),更老的數(shù)據(jù)被更新的可能性更小。Segment A 會被長期占用,空洞空間無法釋放。實際上,這些空洞更有價值,因為一旦釋放,能夠被利用很長時間。所以,cost-benefit 算法兼顧了空洞率和數(shù)據(jù)年齡。它的 pick 算法如公式所示,其中 u 代表有效數(shù)據(jù)率,age 表示 segment 中最新數(shù)據(jù)的年齡。這樣,空洞率比較高的的 segment 會被選中,老的 segment 也有大概率被選中,釋放出更有價值的空洞。
圖片
另外,compaction 的數(shù)據(jù)和用戶的寫入數(shù)據(jù)同樣有不同的冷熱。通常 compaction 的數(shù)據(jù)為長時間沒有寫到的數(shù)據(jù)。將這些數(shù)據(jù)單獨(dú)分流,能夠形成較為穩(wěn)定的 segment。而用戶的寫入的數(shù)據(jù)短時間內(nèi)被寫的可能性比較大,也單獨(dú)放置。這樣進(jìn)行分類后,能夠形成一些致密的 segment,存放老數(shù)據(jù)。頻繁的寫入形成一些稀疏的 segment,這些 segment 可以被反復(fù)利用。
如果想要更好的效果,可以將數(shù)據(jù)流劃分更細(xì),更多地減少寫放大。
圖片
我們統(tǒng)計了線上統(tǒng)計訪問,進(jìn)行回放,控制不同物理空間使用情況下,驗證了寫放大的優(yōu)化效果。
從圖中可以看出,cost-benefit 與貪心算法相比,能夠有效減少寫放大。在高空間占用率的情況下(如 95%),cost-benefit 方式,能夠達(dá)到 1.5 以下的寫放大。而貪心算法則要達(dá)到 4 倍以上。
另外,更多的分流能夠減少寫放大。在貪心算法的情況下,能夠節(jié)省較多的 I/O。cost-benefit 情況下,4 路到 6 路收益不太明顯。
另外可以看出,空間使用率對寫放大也有影響,即較低的空間使用率的情況下,寫放大更好。這也符合直覺,compaction 越晚發(fā)生,segment 形成的空洞越多。
圖片
對于多層 append 系統(tǒng),每一層都期望把本層能用的空間盡量用滿,然后再做 compaction。但是這么做會導(dǎo)致下一層的空間持續(xù)緊張,導(dǎo)致下層寫放大比較嚴(yán)重。例如,如果邏輯層寫的比較滿,遲遲不做 compaction,那么物理層則需要頻繁做 compaction 為邏輯層提供充足寫空間。
系統(tǒng)的整體寫放大,應(yīng)該是每一層的寫放大的乘積。那么,總體寫放大并不是追求單獨(dú)一層低寫放大,而是一個均衡的寫放大,使得整體寫放大較低。
圖片
因此,我們結(jié)合自己的系統(tǒng)特征,設(shè)計了一個均衡 compaction 的點(diǎn)。最上層是用戶數(shù)據(jù)空間,下層是 EC 系統(tǒng)能夠提供的物理空間,中間是寫入 EC 層的數(shù)據(jù)。
我們選擇一個中間點(diǎn)進(jìn)行 compaction 的選擇,如果這個點(diǎn)偏左,說明上層數(shù)據(jù)比較致密,空洞較少,則下層進(jìn)行 compaction。如果這個點(diǎn)偏右,則說明下層致密,上層空洞率較多,觸發(fā)上層的 compaction。
這樣,我們就形成了一個動態(tài)可調(diào)節(jié)的 compaction 點(diǎn),使得上下層的 compaction 都不太大,動態(tài)維護(hù)一個較低的整體 compaction。
圖片
總結(jié)下來,系統(tǒng)有低成本的需求,大規(guī)模場景下多副本由于成本問題,不能滿足需求。因此,我們必要采用糾刪碼的形式組織數(shù)據(jù)。
而糾刪碼本身修改代價比較大,系統(tǒng)設(shè)計當(dāng)中,利用追加寫的方式進(jìn)行修改。并且采用大小寫分離的方式存儲數(shù)據(jù)。分離后,大寫部分產(chǎn)生的 EC 數(shù)據(jù)為變長,采用 append 的引擎,為這種變長分片提供更好的空間分配機(jī)制,同時能夠充分利用硬件追加寫的性能優(yōu)勢。
綜上,百度滄海的塊存儲采用了 2 層 append 方案,規(guī)避了 EC 的修改代價。通過大小寫分離情況,解決了小寫不適合 EC 的情況。同時選擇了合適 pick 算法、數(shù)據(jù)分流、合適的 compaction 點(diǎn)的方式,優(yōu)化了系統(tǒng)的寫放大,能夠達(dá)到低成本下較高的系統(tǒng)性能。
圖片
以上是今天分享的全部內(nèi)容。