vivo HDFS EC 大規(guī)模落地實(shí)踐

Erasure Coding(簡(jiǎn)稱EC),是一種糾刪碼。EC編碼能夠?qū)Σ糠秩笔У臄?shù)據(jù)進(jìn)行數(shù)據(jù)恢復(fù),廣泛應(yīng)用于存儲(chǔ)與通信領(lǐng)域。在Hadoop3.0版本中,作為一種新的冗余存儲(chǔ)的方式引入進(jìn)來(lái)。使用EC編碼的方式替代原來(lái)的三副本存儲(chǔ),保證數(shù)據(jù)可靠性的同時(shí)可以節(jié)約存儲(chǔ)。相應(yīng)地,付出的代價(jià)是讀取性能的下降,對(duì)于訪問(wèn)頻率不高的數(shù)據(jù),使用EC編碼很合適。
vivo目前HDFS集群節(jié)點(diǎn)達(dá)萬(wàn)臺(tái)級(jí)別,數(shù)據(jù)規(guī)模接近EB級(jí)別,并且業(yè)務(wù)數(shù)據(jù)規(guī)模還在以較高速度持續(xù)增長(zhǎng)中。在推進(jìn)壓縮算法緩解存儲(chǔ)壓力的同時(shí),EC編碼的推進(jìn)也是存儲(chǔ)降本的一大有力手段。
1分鐘看圖掌握核心觀點(diǎn)??


01、背景
Reed-Soloman編碼(簡(jiǎn)稱:RS碼),是EC里一種經(jīng)典的編碼算法。下面簡(jiǎn)單介紹一下Reed-Soloman編碼過(guò)程(不涉及數(shù)學(xué)原理的詳細(xì)解析)。
假設(shè)我們的輸入數(shù)據(jù)以D1,D2,...D5的向量來(lái)表示,矩陣B為編碼矩陣,進(jìn)行編碼后得到D和C組成的矩陣,其中D為數(shù)據(jù)塊(data block),C為校驗(yàn)塊(parity block)。我們的數(shù)據(jù)寫(xiě)入都需要經(jīng)過(guò)編碼后才能進(jìn)行存儲(chǔ)。

假設(shè)我們抹除掉了D1,D4,C2。

我們能通過(guò)編碼矩陣得到一個(gè)用于恢復(fù)的矩陣,將這個(gè)矩陣與剩余塊相乘,可得到原來(lái)完整的輸入數(shù)據(jù),再次進(jìn)行編碼后可恢復(fù)C2。

02、存儲(chǔ)布局的改變
EC編碼對(duì)HDFS的應(yīng)用,使數(shù)據(jù)塊存儲(chǔ)的結(jié)構(gòu)發(fā)生了改變。

在傳統(tǒng)三副本的策略中,一個(gè)文件被劃分為不同的塊(block)進(jìn)行存儲(chǔ),一個(gè)數(shù)據(jù)塊對(duì)應(yīng)三個(gè)副本(replication),每個(gè)副本存儲(chǔ)的內(nèi)容完全一致,數(shù)據(jù)的存儲(chǔ)時(shí)連續(xù)的,這種布局稱為連續(xù)塊存儲(chǔ)布局(Contigous Block Layout)。
在EC策略中,一個(gè)文件被劃分為不同的塊組(Block Group)進(jìn)行存儲(chǔ),一個(gè)塊組內(nèi)劃分為多個(gè)內(nèi)部塊(Internal Block),其中,內(nèi)部塊又分為數(shù)據(jù)塊(Data Block)和校驗(yàn)塊(Parity Block)。數(shù)據(jù)塊存儲(chǔ)文件的數(shù)據(jù),校驗(yàn)塊存儲(chǔ)由數(shù)據(jù)塊生成的校驗(yàn)內(nèi)容。一個(gè)塊組內(nèi),可容忍的塊丟失數(shù)量與校驗(yàn)塊數(shù)量相同,如果丟失塊的數(shù)量大于校驗(yàn)塊數(shù)量,則數(shù)據(jù)不可被恢復(fù)。
在塊組中,數(shù)據(jù)并不像三副本策略一樣連續(xù)存儲(chǔ)在一個(gè)塊中,而是將連續(xù)的數(shù)據(jù)拆分為多個(gè)Cell,分散存儲(chǔ)在不同的內(nèi)部塊中,形成一個(gè)個(gè)條帶(Stripe)。這種布局稱為條帶存儲(chǔ)布局(Striped Block Layout)。
我們集群目前采用EC策略RS6-3-1024k,其中6表示塊組中數(shù)據(jù)塊數(shù)量,3表示塊組中校驗(yàn)塊數(shù)量,1024k表示Cell大小。
三副本是HDFS默認(rèn)的冗余存儲(chǔ)方式,優(yōu)點(diǎn)是當(dāng)有機(jī)器宕機(jī),數(shù)據(jù)丟失時(shí),不會(huì)影響用戶的讀取,補(bǔ)塊的方式也僅僅是副本的復(fù)制,簡(jiǎn)單高效。缺點(diǎn)也很明顯,存儲(chǔ)的冗余度高,三副本的存儲(chǔ)冗余度達(dá)到200%。
EC編碼通過(guò)編碼的存儲(chǔ)方式,來(lái)進(jìn)行冗余存儲(chǔ)。優(yōu)點(diǎn)是存儲(chǔ)的冗余度低(具體的冗余度取決于不同的存儲(chǔ)策略),可靠性高。缺點(diǎn)是寫(xiě)入需要編碼,造成性能的下降(大概3-4倍),補(bǔ)塊時(shí)間長(zhǎng)(校驗(yàn)塊越多,補(bǔ)塊時(shí)間越長(zhǎng)),讀取時(shí)如果遇到DN宕機(jī),也需要額外的資源與時(shí)間進(jìn)行解碼恢復(fù)。
策略 | 存儲(chǔ)冗余度 | 最大容忍DN宕機(jī)數(shù)量 |
三副本 | 200% | 2 |
RS-3-2-1024k | 66.6% | 2 |
RS-6-3-1024k | 50% | 3 |
RS-10-4-1024k | 40% | 4 |
03、HDFS EC 碼應(yīng)用實(shí)踐
3.1兼容性問(wèn)題
3.1.1 服務(wù)端
早在2020年,EC已經(jīng)在vivo的HDFS集群中投入使用。EC是Hadoop3.0后推出的新特性,要想正常使用,服務(wù)端和客戶端都需要升級(jí)到3.0或以上版本。
由于離線集群規(guī)模龐大,升級(jí)的調(diào)研和實(shí)施需要耗費(fèi)比較長(zhǎng)的時(shí)間。因此,我們臨時(shí)搭建了一套基于3.1版本的冷備專用集群,使用EC來(lái)存儲(chǔ)冷備數(shù)據(jù),如下圖:

冷備集群使用3.1版本的Yarn,可以同時(shí)訪問(wèn)熱數(shù)據(jù)與冷數(shù)據(jù),3.1版本的HDFS專門用來(lái)存儲(chǔ)EC編碼的冷數(shù)據(jù)。
由于新增冷備集群的方案增加了集群運(yùn)維的成本,架構(gòu)也不夠優(yōu)雅,只是暫時(shí)的解決辦法。在2021年,我們離線集群完成了HDFS從2.6到3.1的全面升級(jí),正式支持EC編碼,在2022年,我們完成絕大部分冷備集群的數(shù)據(jù)到離線集群的遷移,增量數(shù)據(jù)全部寫(xiě)到離線集群中。
3.1.2 客戶端
我們沒(méi)有對(duì)Client2.x客戶端訪問(wèn)EC文件做兼容性的開(kāi)發(fā),更多是通過(guò)推動(dòng)用戶升級(jí)客戶端來(lái)訪問(wèn)EC文件,例如Spark2任務(wù)切換至Spark3任務(wù)。該方案增加了用戶遷移的成本,但同時(shí)也減少了HDFS側(cè)的開(kāi)發(fā)成本,用戶任務(wù)逐步往Spark3遷移也更符合未來(lái)的規(guī)劃。
3.2EC 異步轉(zhuǎn)換
由于EC編碼會(huì)帶來(lái)對(duì)文件讀寫(xiě)性能的下降,對(duì)EC編碼的定位主要應(yīng)用在冷數(shù)據(jù)的存儲(chǔ),業(yè)務(wù)并不直接寫(xiě)EC數(shù)據(jù),而是采用后臺(tái)轉(zhuǎn)儲(chǔ)的方式,把三副本數(shù)據(jù)轉(zhuǎn)儲(chǔ)成EC數(shù)據(jù)。對(duì)不同業(yè)務(wù)而言,對(duì)"冷"的標(biāo)準(zhǔn)都不一致,不能用統(tǒng)一的標(biāo)準(zhǔn)來(lái)衡量數(shù)據(jù)的冷熱。在推廣EC編碼的過(guò)程中,平臺(tái)并不用統(tǒng)一的標(biāo)準(zhǔn)來(lái)“強(qiáng)制”把用戶數(shù)據(jù)轉(zhuǎn)為EC,是否轉(zhuǎn)為EC的最終決定權(quán)在用戶。我們向用戶提供分區(qū)訪問(wèn)頻率的數(shù)據(jù)作為參考,幫助用戶來(lái)了解不同分區(qū)路徑的訪問(wèn)頻次,讓用戶更好地選擇哪些分區(qū)轉(zhuǎn)為EC編碼。用戶可以通過(guò)大數(shù)據(jù)開(kāi)發(fā)者平臺(tái)(Big data developer platform)設(shè)置x天前的數(shù)據(jù)轉(zhuǎn)為EC存儲(chǔ),后臺(tái)程序會(huì)將相應(yīng)分區(qū)通過(guò)Hadoop distcp,將三副本寫(xiě)入到已設(shè)置EC策略的目錄中,再用新目錄替換掉原目錄,其中目錄名稱不變,保證了元數(shù)據(jù)一致,用戶無(wú)需修改代碼。

3.3Distcp 數(shù)據(jù)校驗(yàn)
先來(lái)介紹一下HDFS兩種校驗(yàn)和的方式。
3.3.1 MD5MD5CRC
此方式為HDFS默認(rèn)的校驗(yàn)方式,這種校驗(yàn)方式會(huì)進(jìn)行兩次MD5計(jì)算一次CRC計(jì)算,從名字就可以反映出來(lái)。
- 塊級(jí)校驗(yàn)和:所有chunk CRC的級(jí)聯(lián)的MD5值。(an MD5 of a concatenation of chunk CRCs)
- 文件級(jí)校驗(yàn)和:所有塊校驗(yàn)和的級(jí)聯(lián)的MD5值。(the MD5 of the concatenation of all the block checksums)
由定義可知,這種方式對(duì)于HDFS分塊大小敏感,不同的分塊大小塊級(jí)校驗(yàn)和不一樣,導(dǎo)致文件校驗(yàn)和也會(huì)不一樣。

3.3.2 Composite CRC
Composite CRC一個(gè)新的校驗(yàn)和計(jì)算方式。
當(dāng)計(jì)算塊校驗(yàn)和不是簡(jiǎn)單地將chunk CRC進(jìn)行級(jí)聯(lián)(concatenation),而是將chunk CRC進(jìn)行數(shù)學(xué)式的組合(mathematically compose),計(jì)算文件校驗(yàn)和時(shí)對(duì)文件所有的chunk CRC進(jìn)行數(shù)學(xué)式組合。因此,對(duì)于文件校驗(yàn)和,該計(jì)算方式對(duì)于分塊大小并不敏感。 CRC算法相關(guān)論文。

在數(shù)據(jù)進(jìn)行distcp的過(guò)程中,HDFS會(huì)進(jìn)行校驗(yàn)和校驗(yàn),確保distcp的源數(shù)據(jù)與新數(shù)據(jù)一致,但正如前文所說(shuō),EC編碼會(huì)帶來(lái)存儲(chǔ)布局的改變,相同的文件三副本與EC數(shù)據(jù)存儲(chǔ)的塊大小,塊數(shù)量都不一致,這讓HDFS默認(rèn)的MD5MD5CRC的方式變得不再適用。
需要將校驗(yàn)方式改為COMPOSITE CRC。
可通過(guò) dfs.checksum.combine.mode 改變校驗(yàn)和校驗(yàn)的方式(MD5MD5CRC(默認(rèn)值) or COMPOSITE_CRC)。
即使distcp過(guò)程中會(huì)進(jìn)行校驗(yàn),為了確保萬(wàn)無(wú)一失,我們還會(huì)對(duì)前后的分區(qū)目錄的校驗(yàn)和校驗(yàn)。(目錄校驗(yàn)和計(jì)算方式為將目錄下文件MD5值排序,再進(jìn)行MD5計(jì)算)為了保證轉(zhuǎn)EC前后文件的一致性,多加一道校驗(yàn)的"工序"是值得的。
3.4文件損壞與修復(fù)
文件損壞與丟塊是HDFS EC應(yīng)用繞不開(kāi)的一個(gè)話題,原因是在Hadoop EC特性新推出的過(guò)程中,有若干與文件損壞相關(guān)的bug。EC文件損壞的過(guò)程主要發(fā)生在補(bǔ)塊階段,計(jì)算結(jié)果的不準(zhǔn)確導(dǎo)致了新補(bǔ)的塊與原來(lái)的塊內(nèi)容不一致。我們?cè)贓C推廣的過(guò)程中,也狠狠地踩過(guò)文件損壞的“坑”。如何避免文件損壞,如何對(duì)補(bǔ)塊的結(jié)果進(jìn)行校驗(yàn),如何修復(fù)損壞文件是三個(gè)重要的需要解決的問(wèn)題。
3.4.1 如何避免文件損壞
通過(guò)對(duì)社區(qū)的調(diào)研,我們打了若干的patch來(lái)解決文件損壞與丟塊的問(wèn)題。
Path | 描述 |
HDFS-14768 | Decommisioning的DN會(huì)觸發(fā)EC碼的BUG,導(dǎo)致校驗(yàn)塊的解碼全部為0。 |
HDFS-15240 | 修復(fù)補(bǔ)塊時(shí)buffer污染導(dǎo)致補(bǔ)塊結(jié)果不正確的問(wèn)題。 |
HDFS-16182 | 修復(fù)使用異構(gòu)存儲(chǔ)介質(zhì)時(shí),補(bǔ)塊目標(biāo)數(shù)與預(yù)期不一致,導(dǎo)致文件損壞的問(wèn)題。 |
HDFS-16420 | 修復(fù)Balance時(shí)會(huì)錯(cuò)誤刪除塊的問(wèn)題。 |
3.4.2 對(duì)補(bǔ)塊結(jié)果的校驗(yàn)
我們引入了HDFS-15759,Patch提供了一個(gè)對(duì)EC補(bǔ)塊的校驗(yàn)功能,在DN執(zhí)行補(bǔ)塊任務(wù)時(shí),對(duì)補(bǔ)塊結(jié)果進(jìn)行校驗(yàn)。如果校驗(yàn)失敗會(huì)拋出異常,并且補(bǔ)塊任務(wù)會(huì)進(jìn)行重試。
3.4.3 EC批量校驗(yàn)工具
我們對(duì)開(kāi)源的EC批量校驗(yàn)工具進(jìn)行了定制化的改造,工具能夠?qū)C目錄進(jìn)行批量掃描,掃描出目錄中的損壞的EC文件,在此感謝Stephen O'Donnell對(duì)工具的開(kāi)源。
原理大致如下,對(duì)數(shù)據(jù)塊進(jìn)行EC編碼,通過(guò)比對(duì)新生成的校驗(yàn)塊和原來(lái)的校驗(yàn)塊,來(lái)驗(yàn)證是否存在文件損壞。如果比對(duì)通過(guò),則沒(méi)有文件損壞,如果比對(duì)不通過(guò),則存在文件損壞。

工具支持MR,可以分布式執(zhí)行,此外,也可只對(duì)一個(gè)條帶進(jìn)行比對(duì),只生成校驗(yàn)塊的第一個(gè)條帶,比對(duì)與原校驗(yàn)塊第一個(gè)條帶是否一致,這些都大大提高了批量校驗(yàn)EC文件的效率。
工具地址:https://github.com/sodonnel/hdfs-ec-validator
3.4.4 修復(fù)損壞文件
在我們的集群,絕大部分損壞的文件都是ORC文件,ORC文件發(fā)生損壞時(shí),由于其元數(shù)據(jù)分布的方式,會(huì)出現(xiàn)元數(shù)據(jù)的損壞,ORC無(wú)法解析。
假設(shè)一個(gè)塊組內(nèi),數(shù)據(jù)塊編號(hào)為1~6,校驗(yàn)塊編號(hào)為7~9,數(shù)據(jù)塊1損壞,我們可以通過(guò)讀取數(shù)據(jù)塊2~6加上任一一個(gè)校驗(yàn)塊,得到"完好"的文件,對(duì)于ORC文件而言,判斷是否完好取決于能否正常解析。
HDFS客戶端get文件的時(shí)候默認(rèn)只會(huì)讀取數(shù)據(jù)塊,我們通過(guò)改造HDFS客戶端,使我們能夠讀取塊組內(nèi)指定編號(hào)的塊,通過(guò)各種排列組合,得到一個(gè)"完好"的文件,之后將"完好"的文件覆蓋掉HDFS上的損壞文件,來(lái)達(dá)到文件修復(fù)的目的。

3.5機(jī)器異構(gòu)&存儲(chǔ)策略
由于EC數(shù)據(jù)訪問(wèn)頻率低,將EC數(shù)據(jù)存儲(chǔ)到大存儲(chǔ)的機(jī)器上,利用機(jī)器異構(gòu)降低我們的單位存儲(chǔ)成本。
在HDFS中,如果文件寫(xiě)入的路徑設(shè)置了hot存儲(chǔ)策略的目錄,則會(huì)優(yōu)先把文件存儲(chǔ)到disk存儲(chǔ)介質(zhì)當(dāng)中,如果設(shè)置了cold存儲(chǔ)策略的目錄,則會(huì)優(yōu)先把文件存儲(chǔ)到archive存儲(chǔ)介質(zhì)當(dāng)中。
因此,當(dāng)我們將大存儲(chǔ)機(jī)器的盤都設(shè)置為Archive,并且將EC目錄設(shè)置為Cold存儲(chǔ)策略,即可將EC數(shù)據(jù)存放到大存儲(chǔ)機(jī)器上,使TCO降低,進(jìn)一步實(shí)現(xiàn)存儲(chǔ)降本。

04、總結(jié)與展望
vivo的HDFS集群已存有幾百PB的數(shù)據(jù)采用EC-RS6-3-1024k策略存儲(chǔ),相比三副本EC-RS6-3-1024k方式能帶來(lái)50%的存儲(chǔ)收益,節(jié)省了數(shù)百PB的存儲(chǔ)空間,為公司帶來(lái)了巨大的收益。目前我們推薦用戶將訪問(wèn)頻次較少的數(shù)據(jù)轉(zhuǎn)為EC,因?yàn)镋C會(huì)帶來(lái)讀取性能的下降,如何減少EC帶來(lái)的讀取性能下降?以及后續(xù)細(xì)化對(duì)用戶數(shù)據(jù)的冷熱分層,對(duì)越冷的數(shù)據(jù)采用冗余度越低的EC策略,EC補(bǔ)塊速度優(yōu)化等,都是后續(xù)繼續(xù)大規(guī)模推進(jìn)EC需要解決的重要難題。

































