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