百 PB 級(jí) Hadoop 集群存儲(chǔ)空間治理
現(xiàn)在這個(gè)世道,隨便什么公司什么人都張嘴閉嘴大數(shù)據(jù),連做個(gè)幾十人的問卷都敢叫大數(shù)據(jù)調(diào)查分析。真是無知者無畏。
但也真有不少公司是真的有足夠大的數(shù)據(jù)量的,也確實(shí)是在用心做大數(shù)據(jù)。這些公司通常規(guī)模不小,但盈利不一定理想。就算能穩(wěn)定盈利,也一定有不小的成本壓力。因?yàn)?,大?shù)據(jù),如果真的夠大,是真的很費(fèi)錢。
以我所在的公司為例,每年的服務(wù)器采購成本就已經(jīng)好幾千萬,眼看奔著8位數(shù)去了。
因此我們有很強(qiáng)的節(jié)省成本的動(dòng)力。
另一方面,之前我在思考作為公共部門和基礎(chǔ)設(shè)施部門,在不做業(yè)務(wù)不賺錢的情況下,怎么體現(xiàn)自己的價(jià)值。其中很重要的一點(diǎn)就是,省錢就是賺錢呀,體現(xiàn)在公司收支上效果是差不多的。
在計(jì)算資源可復(fù)用、可靈活調(diào)度的情況下,存儲(chǔ)空間往往是帶來成本的最重要的原因。這篇文章就簡(jiǎn)單梳理下這幾年我們?cè)跀?shù)十 PB 到百 PB 級(jí)別數(shù)據(jù)量下對(duì)存儲(chǔ)空間做的一些治理工作。
1、降低備份數(shù)
大家都知道 HDFS 是靠著 3 副本來保證數(shù)據(jù)的高可用的。但也正是這 3 副本帶來了 3 倍的成本。那要降低成本很自然的就想到降低副本數(shù)。
這個(gè)辦法看起來很笨也很 low,不過確實(shí)能解決問題。當(dāng)然考慮到會(huì)犧牲一定高可用性的風(fēng)險(xiǎn),確實(shí)也不是個(gè)普適性的辦法。
我們把這個(gè)辦法用在臨時(shí)文件上,或者說是線上業(yè)務(wù)不會(huì)直接用到的數(shù)據(jù)上。就算真的丟了,也不會(huì)直接影響到業(yè)務(wù)。要么確實(shí)沒用,丟了就丟了,要么能從其他數(shù)據(jù)恢復(fù)過來。
由于我們對(duì) Hive 庫做了比較嚴(yán)格的權(quán)限管理,但又為了給大家留一定的靈活空間來開發(fā)調(diào)試和做實(shí)驗(yàn),非線上的業(yè)務(wù)都被趕到了 tmp 庫。雖然我們?cè)O(shè)定了定時(shí)刪除的策略,但 tmp 庫的存儲(chǔ)開銷仍然穩(wěn)定在一個(gè)比較高的水平。
于是我們寫了這么個(gè)腳本,定時(shí)遍歷去把 tmp 庫的文件副本數(shù)設(shè)為 2。這樣就把 tmp 庫的存儲(chǔ)消耗降低了 1/3。這可就是幾百萬的 RMB。
當(dāng)然也考慮過修改 Hadoop 的源碼,自動(dòng)在分配 block 的時(shí)候就去把這個(gè)事做了,而不是事后再去改副本數(shù)。簡(jiǎn)單討論了下,覺得一個(gè)小腳本就能解決的問題,事后再做代價(jià)也不大,沒必要去侵入代碼增加復(fù)雜性。
另外值得一提的是,在節(jié)點(diǎn)數(shù)足夠多而網(wǎng)絡(luò)帶寬也足夠大的情況下,如果存儲(chǔ)壓力實(shí)在大,其實(shí)可以考慮把更多的數(shù)據(jù)設(shè)置為 2 副本。因?yàn)榧词褂幸慌_(tái)機(jī)器掛了,也能很快從其他機(jī)器上通過網(wǎng)絡(luò)補(bǔ)回 2 副本。當(dāng)然風(fēng)險(xiǎn)也是有的,如果運(yùn)氣差到家了,2 個(gè)副本所在的機(jī)器同時(shí)都報(bào)廢了,那就真丟數(shù)據(jù)了。
2、壓縮
除了刪數(shù)據(jù)和減少副本外,另一個(gè)很容易想到的辦法就是壓縮。
上面的圖列出了 Hadoop 最常見的幾種壓縮格式。其中 native 決定了對(duì)單個(gè)文件的處理性能,畢竟 Java 在這種計(jì)算密集型的活上還是比不過 C 系列的。而 splitable 決定了一個(gè)文件是否可切分給多個(gè) mapper 處理,也就是文件是否能被并行處理,同樣也會(huì)對(duì)性能造成很大影響。
所以從定性的角度考慮,單看性能,lzo 和 bzip2 似乎是***。
但性能到底怎么樣,還得看實(shí)際的性能測(cè)試結(jié)果,由于時(shí)間實(shí)在太久,一時(shí)找不到當(dāng)時(shí)的數(shù)據(jù)。從網(wǎng)上找了個(gè) benchmark 看看。不要糾結(jié)絕對(duì)數(shù)字,只要知道相對(duì)差距就行。
很明顯,bzip2 壓縮和解壓速率實(shí)在太慢了,差了數(shù)量級(jí)了,***個(gè)被淘汰。
剩下3個(gè),gzip 壓縮比***,也就是最省空間,但處理速率相對(duì)慢些,但也不至于像 bzip2 那么夸張。lzo 和 snappy 無論壓縮比還是處理速度,都很不錯(cuò),再考慮到 splitable,似乎 lzo 應(yīng)該是***。
但實(shí)際上,lzo 有個(gè)不可忽視的特性。lzo 的 splitable 是需要額外的索引文件來支持的,每個(gè)文件都需要有一個(gè)同名的索引文件。并且這個(gè)索引文件需要單獨(dú)去生成。這還不算,索引文件會(huì)導(dǎo)致實(shí)際文件數(shù)多出一倍,這對(duì)于大規(guī)模集群的 NameNode 會(huì)造成巨大的壓力。
綜合上面這些情況,實(shí)際生產(chǎn)環(huán)境,我們采用的是這樣的方式:
- 原始日志采集落地的時(shí)候使用 snappy 壓縮,兼顧存儲(chǔ)空間和處理速度
- 周期性的對(duì)清洗完的日志文件做 archive,并把 snappy 文件轉(zhuǎn)換為 gzip,以節(jié)省空間
- 對(duì)結(jié)構(gòu)化的數(shù)據(jù),主要是 Hive 表,采用 parquet+gzip 的方式,gzip 節(jié)省空間,而相對(duì)于 snappy 的性能劣勢(shì),則由 parquet 的性能優(yōu)勢(shì)來彌補(bǔ)
這樣,就能在存儲(chǔ)空間和性能之間找到比較好的平衡。
3、冷熱分層
在存儲(chǔ)領(lǐng)域有個(gè)很流行的詞,叫異構(gòu)存儲(chǔ)(heterogeneous storage),大白話講就是不同類型的存儲(chǔ)放在一個(gè)系統(tǒng)里,比如 RAM、SSD、DISK 等等。不少類似 Spark 這樣的框架都對(duì)異構(gòu)存儲(chǔ)做了廣泛的支持。
異構(gòu)存儲(chǔ)通常用來解決訪問性能問題,這很容易理解,不同的存儲(chǔ)介質(zhì)訪問速度普遍差了數(shù)量級(jí)。但同時(shí),空間大小和成本也差了數(shù)量級(jí),因此也能被用來節(jié)省成本。
HDFS 定義了兩個(gè)概念來支持異構(gòu)存儲(chǔ)。
***個(gè)概念,Storage Type,用來表示不同類型的存儲(chǔ),包括:
- ARCHIVE,其實(shí)就是更大更便宜的硬盤,花同樣多的 RMB 能存下更多的數(shù)據(jù)。我們生產(chǎn)環(huán)境單臺(tái) 128 TB。
- DISK,常見的普通硬盤,我們生產(chǎn)環(huán)境單臺(tái)空間 48TB。
- SSD,常見的固態(tài)硬盤。
- RAM_DISK,其實(shí)就是內(nèi)存,一般不會(huì)這么奢侈。
很顯然,從上到下越來越快但也越來越貴。
第二個(gè)概念,Storage Policy,用來表示不同的存儲(chǔ)策略,可以對(duì)應(yīng)數(shù)據(jù)的冷熱程度,也就是使用頻次。包括:
- Hot,熱數(shù)據(jù),經(jīng)常被訪問到的數(shù)據(jù),所有副本都保存到 DISK
- Cold,冷數(shù)據(jù),很少訪問的數(shù)據(jù),所有副本都保存到 ARCHIVE
- Warm,溫?cái)?shù)據(jù),介于冷熱之間的數(shù)據(jù),一個(gè)副本保存在 DISK,其他全部在 ARCHIVE
- All_SSD,沒有冷熱對(duì)應(yīng),所有副本保存在 SSD
- One_SSD,沒有冷熱對(duì)應(yīng),一個(gè)副本保存在 SSD,其他都在 DISK
不同版本對(duì)以上兩個(gè)概念的支持可能略有差異。既然是要節(jié)省成本,那 SSD 自然就排除掉,離線大數(shù)據(jù)處理的場(chǎng)景也確實(shí)不太有需要 SSD 的情況。
通常按這個(gè)思路去劃分?jǐn)?shù)據(jù)冷熱,然后設(shè)置 Storage Policy 做就能解決大部分問題了。至于怎樣定義和衡量數(shù)據(jù)冷熱,就又是一個(gè)可以另開一篇的話題了。簡(jiǎn)單提點(diǎn)思路,可以按照數(shù)據(jù)時(shí)間和訪問次數(shù)兩個(gè)維度去劃分區(qū)間,從 HDFS 審計(jì)日志統(tǒng)計(jì)結(jié)果。
除了社區(qū)的默認(rèn)支持外,我們?cè)?hot warm cold 的基礎(chǔ)上,又加了一層 frozen 層,用來保存最冷的數(shù)據(jù)。
考慮到 ARCHIVE 已經(jīng)是***的存儲(chǔ)介質(zhì)了,具體 frozen 的效果并沒有也沒辦法再在 Storage Type 上做文章。我們把目光轉(zhuǎn)移到了***節(jié)提到的降低備份數(shù)上。
當(dāng)然不能是簡(jiǎn)單的設(shè)置 repica,不然這部分就直接放***節(jié)講了。我們使用的是 HDFS 的糾刪碼(erasure code)。
通俗點(diǎn)說就是 HDFS 上的 RAID。RAID 這個(gè)思路其實(shí)早就被 Facebook 和騰訊這樣的公司在生產(chǎn)環(huán)境大規(guī)模實(shí)踐過,畢竟他們肯定是***遇到也最有動(dòng)力解決存儲(chǔ)成本問題的公司。可惜要么版本古老不再更新維護(hù),要么閉源沒有回饋社區(qū)。
好在 Hadoop 3.0 正式支持了這個(gè)功能。當(dāng)然,缺點(diǎn)也是有的。首先,代碼穩(wěn)定性有待考驗(yàn),畢竟業(yè)界還沒有大規(guī)模的 3.0 踩坑經(jīng)驗(yàn);其次,CDH 目前還沒有發(fā)布 Hadoop 3.0 的正式版,因此部署維護(hù)就沒那么方便和統(tǒng)一了。
所以,只有真的非常老和很長(zhǎng)時(shí)間都不用的數(shù)據(jù)才適合設(shè)置為 frozen 放在啟用了糾刪碼的 3.0 集群上。
按我們生產(chǎn)環(huán)境 archive 機(jī)器成本占 disk 機(jī)器大概 1/3 算,分層存儲(chǔ)的空間和成本開銷對(duì)比如下:
看到這個(gè)表格,相信大家都有足夠的動(dòng)力去做分層存儲(chǔ)了。
4、大存儲(chǔ)機(jī)器
但是,最近幾年,有個(gè)說法開始逐漸顛覆大家的傳統(tǒng)認(rèn)知。
說沒有必要再分 DISK、ARCHIVE 兩種機(jī)型,直接全部上大存儲(chǔ)機(jī)器。
考慮到隨著萬兆網(wǎng)卡的普及,再加上網(wǎng)卡綁定、交換機(jī)性能的提升等,網(wǎng)絡(luò) IO 已經(jīng)不再是瓶頸。
同時(shí)考慮到數(shù)據(jù)規(guī)模,DISK/Memory 比也沒有意義,因此也不用顧及計(jì)算資源相對(duì)少的問題。更何況還有相當(dāng)數(shù)量的冷數(shù)據(jù)躺在哪里,根本不需要為它們預(yù)留計(jì)算資源。
看起來很有道理,也值得一試。后面稍稍沒那么忙了,我們會(huì)集中測(cè)試對(duì)比下性能。大家有經(jīng)驗(yàn)的可以留言一起探討下。
主要內(nèi)容就是這樣,其他零散的治理方法就略過了。
隨著數(shù)據(jù)量的增長(zhǎng),元數(shù)據(jù)也會(huì)急劇膨脹,很快 NameNode 就會(huì)成為集群的瓶頸。解決方法是 HDFS Federation,我們?cè)谏a(chǎn)環(huán)境已經(jīng)有了不錯(cuò)的實(shí)踐。但這又是一個(gè)復(fù)雜的話題了,下次有機(jī)會(huì)單獨(dú)開一篇再細(xì)說。