百PB級Hadoop集羣存儲空間治理方案

    現在這個世道,隨便什麼公司什麼人都張嘴閉嘴大數據,連做個幾十人的問卷都敢叫大數據調查分析。真是無知者無畏。

但也真有不少公司是真的有足夠大的數據量的,也確實是在用心做大數據。這些公司通常規模不小,但盈利不一定理想。就算能穩定盈利,也一定有不小的成本壓力。因爲,大數據如果真的夠大,是真的很費錢。以我所在的公司爲例,每年的服務器採購成本就已經好幾千萬,眼看奔着8位數去了。因此我們有很強的節省成本的動力。

    另一方面,之前我在思考作爲公共部門和基礎設施部門,在不做業務不賺錢的情況下,怎麼體現自己的價值。其中很重要的一點就是,省錢就是賺錢呀,體現在公司收支上效果是差不多的。在計算資源可複用、可靈活調度的情況下,存儲空間往往是帶來成本的最重要的原因。這篇文章就簡單梳理下這幾年我們在數十 PB 到百 PB 級別數據量下對存儲空間做的一些治理工作。

一、降低備份數

    大家都知道 HDFS 是靠着 3 副本來保證數據的高可用的。但也正是這 3 副本帶來了 3 倍的成本。那要降低成本很自然的就想到降低副本數。這個辦法看起來很笨也很 low,不過確實能解決問題。當然考慮到會犧牲一定高可用性的風險,確實也不是個普適性的辦法。

    我們把這個辦法用在臨時文件上,或者說是線上業務不會直接用到的數據上。就算真的丟了,也不會直接影響到業務。要麼確實沒用,丟了就丟了,要麼能從其他數據恢復過來。

    由於我們對 Hive 庫做了比較嚴格的權限管理,但又爲了給大家留一定的靈活空間來開發調試和做實驗,非線上的業務都被趕到了 tmp 庫。雖然我們設定了定時刪除的策略,但 tmp 庫的存儲開銷仍然穩定在一個比較高的水平。於是我們寫了這麼個腳本,定時遍歷去把 tmp 庫的文件副本數設爲 2。這樣就把 tmp 庫的存儲消耗降低了 1/3。這可就是幾百萬的 RMB。

    當然也考慮過修改 Hadoop 的源碼,自動在分配 block 的時候就去把這個事做了,而不是事後再去改副本數。簡單討論了下,覺得一個小腳本就能解決的問題,事後再做代價也不大,沒必要去侵入代碼增加複雜性。

    另外值得一提的是,在節點數足夠多而網絡帶寬也足夠大的情況下,如果存儲壓力實在大,其實可以考慮把更多的數據設置爲 2 副本。因爲即使有一臺機器掛了,也能很快從其他機器上通過網絡補回 2 副本。當然風險也是有的,如果運氣差到家了,2 個副本所在的機器同時都報廢了,那就真丟數據了。

二、壓縮

除了刪數據和減少副本外,另一個很容易想到的辦法就是壓縮

    上面的圖列出了 Hadoop 最常見的幾種壓縮格式。其中 native 決定了對單個文件的處理性能,畢竟 Java 在這種計算密集型的活上還是比不過 C 系列的。而 splitable 決定了一個文件是否可切分給多個 mapper 處理,也就是文件是否能被並行處理,同樣也會對性能造成很大影響。所以從定性的角度考慮,單看性能,lzo 和 bzip2 似乎是首選。

    但性能到底怎麼樣,還得看實際的性能測試結果,由於時間實在太久,一時找不到當時的數據。從網上找了個 benchmark 看看。不要糾結絕對數字,只要知道相對差距就行。

很明顯,bzip2 壓縮和解壓速率實在太慢了,差了數量級了,第一個被淘汰。剩下3個,gzip 壓縮比最高,也就是最省空間,但處理速率相對慢些,但也不至於像 bzip2 那麼誇張。lzo 和 snappy 無論壓縮比還是處理速度,都很不錯,再考慮到 splitable,似乎 lzo 應該是首選。

    但實際上,lzo 有個不可忽視的特性。lzo 的 splitable 是需要額外的索引文件來支持的,每個文件都需要有一個同名的索引文件。並且這個索引文件需要單獨去生成。這還不算,索引文件會導致實際文件數多出一倍,這對於大規模集羣的 NameNode 會造成巨大的壓力。

    綜合上面這些情況,實際生產環境,我們採用的是這樣的方式:

  • 原始日誌採集落地的時候使用 snappy 壓縮,兼顧存儲空間和處理速度。

  • 週期性的對清洗完的日誌文件做 archive,並把 snappy 文件轉換爲 gzip,以節省空間。

  • 對結構化的數據,主要是 Hive 表,採用 parquet+gzip 的方式,gzip 節省空間,而相對於 snappy 的性能劣勢,則由 parquet 的性能優勢來彌補。

    這樣,就能在存儲空間和性能之間找到比較好的平衡。

 

三、冷熱分層

   在存儲領域有個很流行的詞,叫異構存儲(heterogeneous storage),大白話講就是不同類型的存儲放在一個系統裏,比如 RAM、SSD、DISK 等等。不少類似 Spark 這樣的框架都對異構存儲做了廣泛的支持。異構存儲通常用來解決訪問性能問題,這很容易理解,不同的存儲介質訪問速度普遍差了數量級。但同時,空間大小和成本也差了數量級,因此也能被用來節省成本。

HDFS 定義了兩個概念來支持異構存儲。

第一個概念:Storage Type

用來表示不同類型的存儲,包括:

  • ARCHIVE,其實就是更大更便宜的硬盤,花同樣多的 RMB 能存下更多的數據。我們生產環境單臺 128 TB。

  • DISK,常見的普通硬盤,我們生產環境單臺空間 48TB。

  • SSD,常見的固態硬盤。

  • RAM_DISK,其實就是內存,一般不會這麼奢侈。

很顯然,從上到下越來越快但也越來越貴。

第二個概念:Storage Policy

用來表示不同的存儲策略,可以對應數據的冷熱程度,也就是使用頻次。包括:

  • Hot,熱數據,經常被訪問到的數據,所有副本都保存到 DISK

  • Cold,冷數據,很少訪問的數據,所有副本都保存到 ARCHIVE

  • Warm,溫數據,介於冷熱之間的數據,一個副本保存在 DISK,其他全部在 ARCHIVE

  • All_SSD,沒有冷熱對應,所有副本保存在 SSD

  • One_SSD,沒有冷熱對應,一個副本保存在 SSD,其他都在 DISK

    不同版本對以上兩個概念的支持可能略有差異。既然是要節省成本,那 SSD 自然就排除掉,離線大數據處理的場景也確實不太有需要 SSD 的情況

    通常按這個思路去劃分數據冷熱,然後設置 Storage Policy 做就能解決大部分問題了。至於怎樣定義和衡量數據冷熱,就又是一個可以另開一篇的話題了。簡單提點思路,可以按照數據時間和訪問次數兩個維度去劃分區間,從 HDFS 審計日誌統計結果。

除了社區的默認支持外,我們在 hot warm cold 的基礎上,又加了一層 frozen 層,用來保存最冷的數據。

    考慮到 ARCHIVE 已經是最便宜的存儲介質了,具體 frozen 的效果並沒有也沒辦法再在 Storage Type 上做文章。我們把目光轉移到了第一節提到的降低備份數上。當然不能是簡單的設置 repica,不然這部分就直接放第一節講了。我們使用的是 HDFS 的糾刪碼(erasure code)。

    通俗點說就是 HDFS 上的 RAID。RAID 這個思路其實早就被 Facebook 和騰訊這樣的公司在生產環境大規模實踐過,畢竟他們肯定是最先遇到也最有動力解決存儲成本問題的公司。可惜要麼版本古老不再更新維護,要麼閉源沒有回饋社區。

    好在 Hadoop 3.0 正式支持了這個功能。當然,缺點也是有的。首先,代碼穩定性有待考驗,畢竟業界還沒有大規模的 3.0 踩坑經驗;其次,CDH 目前還沒有發佈 Hadoop 3.0 的正式版,因此部署維護就沒那麼方便和統一了。所以,只有真的非常老和很長時間都不用的數據才適合設置爲 frozen 放在啓用了糾刪碼的 3.0 集羣上。

    按我們生產環境 archive 機器成本佔 disk 機器大概 1/3 算,分層存儲的空間和成本開銷對比如下:

看到這個表格,相信大家都有足夠的動力去做分層存儲了。

 

四、大存儲機器

    但是,最近幾年,有個說法開始逐漸顛覆大家的傳統認知,說沒有必要再分 DISK、ARCHIVE 兩種機型,直接全部上大存儲機器。考慮到隨着萬兆網卡的普及,再加上網卡綁定、交換機性能的提升等,網絡 IO 已經不再是瓶頸。同時考慮到數據規模,DISK/Memory 比也沒有意義,因此也不用顧及計算資源相對少的問題。更何況還有相當數量的冷數據躺在哪裏,根本不需要爲它們預留計算資源。 

    隨着數據量的增長,元數據也會急劇膨脹,很快 NameNode 就會成爲集羣的瓶頸。解決方法是 HDFS Federation,我們在生產環境已經有了不錯的實踐。但這又是一個複雜的話題了,下次有機會單獨開一篇再細說。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章