高性能、云原生湖倉一體存儲架構探秘
一、湖倉一體存儲架構的演進
1、存儲架構的演進階段
大數據存儲系統的演進,分為兩個階段:機房時代和云計算時代。
第一個階段,也是最早 Hadoop誕生的時代,這個時代主要以機房的系統為主, HDFS 基本上是唯一的存儲選型方案。
隨著云計算的普及和發展,對象存儲逐漸成為企業主流的存儲方案。尤其是在數據湖架構中,對象存儲以其高度可擴展性和對多樣化數據類型的支持,成為一種流行的底層存儲解決方案。我們將回顧并對比HDFS和對象存儲的架構,探討它們各自的優劣勢以及發展趨勢。同時也會探討云原生的數據湖存儲架構應該如何設計。
如果從本質上去分析 HDFS 和和對象存儲的架構設計,會發現其實是兩個完全不一樣的存儲系統。未來在云原生時代里的存儲系統,為大數據湖倉一體提供存儲底座,應該具備哪些特征呢?后面我們會對此進行探討。
2、HDFS 的特征
HDFS 起源于 GFS ( Google File system ) , 于2006年正式發布。它的特點包括獨立的元數據存儲(NameNode)、多副本、存算耦合等。整個 HDFS 設計,對于大文件存儲相對來說更友好,對于小文件沒有那么友好。在存儲的規模上,一般單個命名空間(Namespace)在億這個量級。如果有更大量級的數據存儲,需要做一些擴展性的架構調整。
3、對象存儲的特征
對象存儲 S3 也是于2006年發布,但它發布之初的目標其實是存儲海量的非結構化數據,并不是給大數據生態使用,所以對象存儲的架構設計和 HDFS 完全不一樣。它主打的特點,包括存儲成本低、數據的持久性足夠高等方面。它的 API 是基于 HTTP 協議,元數據設計是扁平的 KV 結構,扁平的元數據設計在大數據場景中會帶來一些問題。和 HDFS 一樣,它的數據也是不支持修改的。在一致性上,對象存儲以最終一致性為主,部分的云廠或者部分接口可以實現強一致性。
二、不同類型存儲系統比較
下面整體對比一下前面提到的 HDFS 和對象存儲在不同維度的特性。
首先存儲規模直接決定了數據平臺或者整個大數據系統能夠支撐的業務數據量,相比HDFS,對象存儲能做到更大的存儲規模。在日常的數據任務中,比如 ETL 或者ad-hoc,元數據操作性能會影響整體的任務效率,這一點對象存儲的性能要遠遠弱于HDFS。運維復雜度也是影響存儲選型的關鍵因素,HDFS的維護成本相比對象存儲會高不少,這其中既包括人力成本,也包括為了保證高可用和擴展性額外搭建的一些組件等。
1、HDFS的阿喀琉斯之踵-NameNode
HDFS 最大的瓶頸是 NameNode。NameNode 最開始的設計是模仿 GFS 的 Master,這是一個單點設計,所以 HDFS 也有同樣的問題。
在單點的 NameNode 擴展性問題上,社區做了一些嘗試,比如 ViewFs + Federation 的方案,后面又推出了RBF(Router-based Federation)方案,本質上是為了解決單一命名空間下 NameNode的擴展性問題,通過多集群橫向擴展的方式保證 HDFS 集群存儲容量的規模不會受到大的限制。
除了存儲規模以外,另外一個問題就是高可用問題。在單一集群里面 NameNode 是一個單點,所以后來有了 Standby 的 NameNode,再往后有了 JournalNode。歸根結底,所有這些組件、架構都是為了保證整個 HDFS 存儲集群能夠滿足高可用的需求,而不是一旦 Active NameNode 宕機之后整個大數據集群就不可用了。
2、對象存儲的阿喀琉斯之踵-元數據
對象存儲的問題也跟元數據相關。前面提到了對象存儲的元數據設計是一個扁平的 KV 結構。上圖中的foo目錄有這么多子目錄或者子文件,從對象存儲角度來說,它并不是目錄結構。我們在傳統的文件系統里面看到的是樹狀的目錄結構,但在對象存儲的設計里面并不存在一個目錄樹,而是一維扁平的 KV 結構,再通過“/” 分隔符來模擬目錄樹。
如果要在對象存儲里面實現目錄的重命名,例如將foo這個目錄重命名為 bar 目錄,對象存儲的實現上會有這樣一些步驟:第一步需要先遞歸地拷貝,如果是很深的目錄,那需要去遞歸拷貝整個目錄的數據到以 bar 為前綴的位置;第二步是更新內部的一些索引;最后把原始的 foo 目錄下的相關數據都刪掉。
整個流程雖然看起來只是一步重命名文件夾的操作,但在對象存儲內部拆分成了幾個大的步驟,每個步驟其實看起來都不是特別的輕量,特別是第一步和第三步。
我們自然會有一個疑問,在這個過程中,尤其是當要重命名一個很大數據量的目錄時,一致性如何保證?其實對象存儲是沒有辦法保證的。社區有很多的組件去嘗試解決,或者基于對象存儲的接口去優化。但也只能是盡量去規避一致性問題,并不能完全解決。因為對象存儲架構設計上的問題是沒有辦法通過外層的組件簡單繞過的。
3、對象存儲元數據性能及API限制
在數據湖的組件里面,不管是 Hudi 還是 Iceberg,都提到過對象存儲的一些問題,比如上面這個表格是 Hudi 文檔里面提到的,在對象存儲上如果要 List 一個目錄,隨著目錄的文件數的增多,它的延遲會逐步地增長,所以 Hudi 社區才有了 Metadata Table 設計。
Iceberg 在文檔里面也提到對象存儲會有一些基于某一個固定前綴的 API QPS 限制,這樣就會導致頻繁訪問的目錄或者大的數據集如果觸碰到這個 API QPS 限制,任務的穩定性會直接受到影響。特別是當你的數據平臺的規模變得比較大以后,就很容易觸碰到云上對象存儲的 API QPS 限制。所以 Iceberg 有了 ObjectStorageLocationProvider,去盡量規避這個問題。它本質上是一種規避的實現方式,在不同的Key 前面加一個隨機的哈希,這個哈希就是為了盡量把基于前綴的 QPS 限制分散到不同的前綴,從而避免很快觸碰到 API QPS 限制。
三、探索湖倉一體架構未來的存儲選型
假設現在從 0 開始去設計,基于當下云計算或者云原生的環境去構建一個更適合現在和未來的存儲系統,它應該具備哪些能力呢?
1、技術關鍵點
這里列了對于大部分場景來說都比較重要的一些點:
首先最重要的就是擴展性的問題,隨著大數據平臺的架構從數倉、到數據湖、到湖倉一體不斷演進,對于平臺存儲容量的要求會越來越高,不僅僅是滿足以前傳統數倉的存儲需求,還要盡量多地去涵蓋越來越多的業務,以前在不同的存儲系統里面管理的數據,接下來可能需要在一個地方統一存儲和管理,避免數據孤島的問題。
第二個很重要的點是高可用問題。整個系統肯定要具備高可用的能力,不能只有擴展性沒有高可用,否則也是無法滿足生產需求的。
第三點是性能問題。不能為了存儲大容量的數據,就以犧牲性能為代價,需要一定的優化策略保證性能,包括元數據的性能以及數據讀寫的性能。
接下來是盡量多地利用云的優勢,云最大的特性就是彈性,計算和存儲都可以做到彈性。如果整個存儲系統架構不能夠適配云的彈性伸縮特征,還沿用以前機房的存儲架構,就不能最大化發揮云的特點。
云上天然是存算分離的場景,如何將整個生態里面的計算組件和存儲組件分離,分離后還能保證整體的計算效率以及擴展性等,都是底層的存儲系統需要考慮的問題。
小文件管理更多是數據湖需要考慮的問題,傳統的大數據平臺可能還是以大文件為主,但是小文件問題會隨著 AI 或者其它領域的數據進來后越來越凸顯。
針對以上每一個技術關鍵點都會有一些對應的解決思路,如上圖所示。
2、JuiceFS
今天給大家介紹的 JuiceFS,定位是強一致性的分布式文件系統,可以認為這個設計目標是用來完整替代 HDFS 的。
JuiceFS的整體架構分為三塊,跟 HDFS 很像,元數據的存儲、數據的存儲、以及不同客戶端的接口。但其實每一塊都會有一些不一樣的設計。
首先元數據在 JuiceFS 里面是插件式的引擎設計,不同的場景可以選擇不同的數據庫,比如Redis、MySQL、TiKV等等,你可以根據業務場景、業務需求,挑選最合適的數據庫來作為JuiceFS的元數據引擎。
數據存儲方面, JuiceFS 主要基于對象存儲,可以最大化利用云上的存儲資源,所有數據都放到對象存儲里,但并不是簡單地寫到對象存儲里就完了,通過 JuiceFS 客戶端寫進來的數據,會做一些格式處理(類似HDFS DataNode的block設計),元數據會盡量不依賴對象存儲的元數據,因為前面提到了對象存儲的元數據是有很多問題的,如一致性問題、性能問題。JuiceFS不依賴對象存儲的元數據,而是由自己獨立的元數據存儲來承擔所有的元數據請求。
元數據引擎可以橫向擴展,對于海量級(比如百億級)的文件,不管是大文件還是小文件,都能夠很輕松地存儲。在JuiceFS用戶的生產環境里也的確做到了百億級規模,很好地證明了存儲系統具有優秀的擴展性。
緩存是很重要的特性,特別是在存算分離的場景下。如果需要升級到存算分離的架構肯定要考慮緩存功能,不管是元數據的緩存,還是數據的緩存都是有必要的。
四、湖倉一體架構在JuiceFS上的實踐
1、湖倉一體架構
這是整體架構圖,最下面既包含傳統的結構化數據,也有很多半結構化和非結構化數據。存儲層是 JuiceFS 結合對象存儲提供統一的存儲底座。
再往上是 Delta Lake、 Hudi 或者 Iceberg 這樣的數據管理層,它會基于底層的存儲系統 JuiceFS 、 HDFS 或者對象存儲之上,再對整個數倉進行管理。
然后是各種查詢引擎、BI 工具、計算引擎接入不同的管理層組件。
2、元數據性能比較
上圖中比較的是以 OSS 為代表的對象存儲,以及 HDFS 和 JuiceFS 。左邊是元數據的 Latency,這個值越低越好;右邊是吞吐,值越大越好。
首先看藍色的對象存儲和另外兩個相比,Latency 在不同的元數據上操作的差別會很大。特別是前面提到的 Rename操作,相比另外兩個存儲系統來說,在對象存儲上有非常大的性能下降。HDFS 和 JuiceFS 在架構設計上是相似的,都有獨立的元數據存儲,所以不管是 Latency 還是吞吐上都能做到比較快的程度。右邊這個圖中 JuiceFS 相比 HDFS 在吞吐上甚至能做得更好。
3、數據查詢性能比較
上圖是數據查詢性能比較。左邊這個圖是用 Spark 在對象存儲和 JuiceFS 上做的 TPC-DS 查詢測試。右邊這個圖是用 Presto 在 HDFS 和 JuiceFS 的測試。
左邊圖中可以看到,在查詢性能上, JuiceFS 相比直接使用對象存儲能有成倍的性能提升,特別是在一些相對比較復雜的查詢上(比如第九個查詢)的性能提升會更加明顯。
右邊圖中可以看到, JuiceFS 在充分緩存的情況下,存算分離的架構也能夠做到和 HDFS 查詢性能相當的程度。
所以綜合來看,不管是元數據的性能測試,還是整體基于 TPC-DS 的查詢測試,JuiceFS都能夠做到性能和HDFS一致,同時相比對象存儲有著大幅的性能優勢。
四、Q&A
Q1: HDFS 不是存算分離架構是不是意味著會被淘汰?
A1: 我覺得從中短期來看的話, HDFS 肯定不會被淘汰,因為它還是大數據生態里面事實意義上的標準。只是在大數據平臺上云之后,大家會重新思考在云上怎么搭建大數據平臺的存儲系統。有些公司可能還會選擇把機房的整套基礎設施都搬到云上,其實這樣做在成本上可能會比在機房里還高一些,不過至少保證整體架構是經過驗證的,但就達不到上云的初衷,沒法更多地利用云的特性。如果還是把基于 HDFS 的存算耦合架構搬到云上其實沒有得到任何云的好處,所以很多公司開始想要去選擇對象存儲或者類似JuiceFS的新一代存儲系統也是基于這樣一個原因。
Q2: S3 對象存儲設計本身有 KV 設計的缺陷,那是不是也意味著淘汰?
A2: 是不一樣的定位,因為 S3 最初的定位不是為大數據生態設計,它的定位是很清晰的:存儲海量的非結構化數據,很容易擴展,可靠性足夠高,數據不能丟,存儲的成本要足夠的低(所以它用了像 EC這樣的技術)。這些都是 S3 的優勢,只要有這樣需求的場景,都會非常適用。但像大數據或者 AI 這類場景比較特別的一點在于,并不只是需要滿足存儲規模的需求就夠了,還需要滿足各種各樣其他的需求,比如性能的需求,整體對于業務的影響等等我們認為更苛刻的需求,S3或對象存儲是沒有辦法簡單滿足的,所以才需要有一些新的設計或者新的系統,怎么基于對象存儲做進一步的改進和提升。S3 本身肯定是不會被淘汰的。
Q3: 存算分離架構,存算一體,哪個存儲架構更適合哪些場景?
A3: 一般講存算分離或者存算耦合,更多是基于你當下的整體架構。如果是考慮在云上搭建整個數據平臺或者 AI 平臺的話,天然地就會去考慮更多利用云上的資源。云上資源的彈性能力要最大化發揮必然是要去朝著存算分離這個方向走的。即使一開始可能是存算耦合的架構,長遠來看還是需要去朝存算分離架構走。如果沒有必要上云,而是在機房里有自己的一套私有云架構,用不用存算分離或者存算耦合,區別不大。更多還是怎么在存算分離的架構下發揮云的優勢。
Q4: JuiceFS 和 Alluxio 的差異。
A4: 這個問題問得挺好。在 JuiceFS 官方文檔里面有專門一篇比較 JuiceFS 和Alluxio,大家有興趣可以去官方文檔里看一下。簡單講一下,JuiceFS 的設計目標或定位是分布式文件系統,對標的是 HDFS 這類傳統的分布式文件系統。我理解Alluxio的設計定位更多是一個緩存層,這個 緩存層的目標并不是實現完整的文件系統特性,比如不需要去完整地兼容 POSIX,不需要提供各種各樣針對非大數據以外場景的特性。但是 JuiceFS 定位為分布式文件系統,所以我們需要考慮很多文件系統需要考慮的點。可能 Alluxio和 JuiceFS 在某些特性上(比如緩存)有一些重合的地方,不代表這兩個項目的設計方向是一樣的。
Q5: 存算分離架構效率比一體是不是要差一些。
A5: 如果只是簡單地把存儲和計算分離,不做任何優化,效率肯定是會變低的。即使到現在網絡硬件技術已經發展得很好的情況下,可能還是沒有本地的 I/O 效率高。所以只是簡單地拆分存儲和計算效率肯定會下降,因此才需要考慮存算分離之后怎么進一步地去優化性能。盡量不要降低業務或損害業務的一些日常指標。