豆瓣成立于 2005 年,是中國最早的社交網站之一。在 2009 到 2019 的十年間,豆瓣數據平臺經歷了幾輪變遷,形成了 DPark + Mesos + MooseFS 的架構。
由機房全面上云的過程中,原有這套架構并不能很好的利用云的特性,豆瓣需要做一次全面的重新選型,既要考慮未來十年的發展趨勢,也需要找到與現有組件兼容且平滑過渡的解決方案。一番改造后, 豆瓣數據平臺目前形成了 Spark + Kubernetes + JuiceFS 的云上數據湖架構,本文將分享此次選型升級的整體歷程。
01 豆瓣早期數據平臺
在 2019 年,豆瓣所使用的數據平臺主要由以下組件構成:
Gentoo Linux,內部使用的 Linux 發行版;MooseFS ,分布式文件系統;Apache Mesos 負責整個集群的資源管理,以及 Dpark 作為分布式計算框架提供給開發者使用。
(豆瓣早期數據平臺架構)
從上圖可以看到在這個數據平臺中,計算和存儲是一體的,每個計算任務是由 Mesos 進行調度的。計算任務的 I/O 操作都是通過 MooseFS 的 Master 獲取元數據,并在本地獲取需要計算的數據。此外,GPU 計算集群也是通過 Mesos 進行管理,不同的是, GPU 會基于顯存進行共享。
平臺組件介紹
Gentoo Linux
Gentoo Linux 是一個較為小眾的 Linux 發行版,具有幾乎無限制的適應性特性,是一個原發行版。Gentoo Linux 采用滾動更新的方式,所有軟件包都直接從社區中獲取二進制包,我們則通過源代碼構建我們所需的軟件包。Gentoo Linux 有一個強大的包管理器,使用它也會帶來很多便利,也同時存在一些問題。比如,滾動更新的速度非??欤珜τ诜掌鱽碚f,可能存在一定的不穩定性。
使用源代碼構建軟件包的好處是當社區沒有預編譯好我們所需的軟件包時,我們可以非常簡單地構建出自己所需的軟件包,并且當已有的軟件包無法滿足我們的需求時,也可以很容易地進行定制調整。但這也會帶來較高的維護成本。
另外,如果所有軟件包都能按照規范進行編寫的話,依賴沖突問題幾乎是不存在的,因為在打包過程中就已經可以發現。但實際情況是并不是所有軟件包都能遵守一個好的依賴描述的約定,因此依賴沖突問題可能仍然存在。
Gentoo Linux 是較為小眾的選擇,盡管社區質量很高,但是用戶也比較少,一些新項目可能沒有用戶進行足夠的測試,我們在實際使用過程中會遇到各種各樣的問題。這些問題大部分需要我們自己解決,如果等待其他人回復的話,響應會比較慢。
MooseFS
MooseFS 是一個開源的、符合 POSIX 標準的分布式文件系統,它只使用 FUSE 作為 I/O 接口,并擁有分布式文件系統的標準特性,如容錯、高可用、高性能和可擴展性。
對于幾乎所有需要使用標準文件系統的場景,我們都使用 MooseFS 作為替代品,并在其基礎上開發了一些自己的小工具。例如,我們可以直接使用分布式文件系統來處理 CDN 的回源。在早期版本中,MooseFS 沒有主節點的備份功能,因此我們開發了一個 ShadowMaster 作為元數據的熱備節點,并編寫了一些分析 MooseFS 元數據的工具,以解決一些運維問題。作為一個存儲設施,MooseFS 整體比較穩定,并且沒有出現重大的問題。
Apache Mesos
Mesos 是一個開源的集群管理器,與YARN 有所不同,它提供公平分配資源的框架,并支持資源隔離,例如 CPU 或內存。Mesos 早在 2010 年就被 Twitter 采用, IBM 在 2013 年開始使用。
Dpark
由于公司全員使用 Python,因此使用了 Python 版的 Spark,即 Dpark,它擴展了RDD API,并提供了 DStream。
公司內部還開發了一些小工具,例如 drun 和 mrun,可以通過 Dpark 將任意 Bash 腳本或數據任務提交到 Mesos 集群,并支持 MPI 相關的任務提交。Dgrep 是用于快速查詢日志的小工具,JuiceFS 也提供了類似的工具。雖然 Dpark 本身可以容器化,但公司主要的數據任務是在物理服務器上運行的。支持容器化可以讓場內任務更好地利用線上業務的模型代碼。
02 平臺演進的思考
在 2019 年,公司決定將基礎設施轉移到云端并實現計算和存儲分離,以提高平臺的靈活性。由于以前的計算任務在物理機上運行,隨著時間的推移,出現了越來越多的依賴沖突問題,維護難度不斷增加。
同時,公司希望內部平臺能夠與當前的大數據生態系統進行交互,而不僅僅是處理文本日志或無結構化、半結構化的數據。此外,公司還希望提高數據查詢效率,現有平臺上存儲的數據都是行存儲,查詢效率很低。最終,公司決定重新設計一個平臺來解決這些問題。
平臺演進時,我們沒有非常強的兼容性需求。只要成本收益合理,我們就可以考慮將整個平臺替換掉。這就像是環法自行車比賽中,如果車有問題就會考慮換車,而不是只換輪子。在更換平臺時,我們如果發現現有平臺的任務無法直接替換,可以先保留它們。在切換過程中,我們有以下主要需求:
? Python 是最優先考慮的開發語言。
?必須保留 FUSE 接口,不能直接切換到 HDFS 或者 S3。
?盡可能統一基礎設施,已經選用了部分 Kubernetes,就放棄了 Mesos 或其他備選項。
?新平臺的學習成本應盡可能低,讓數據組和算法組的同事能夠以最低的成本切換到新的計算平臺上。
03 云上構建數據平臺
目前的云上數據平臺幾乎是全部替換了,Gentoo Linux 的開發環境變成了 Debian based container 的環境, MooseFS 是換用了現在的 JuiceFS,資源管理使用了 Kubernetrs,計算任務的開發框架使用了 Spark,整體進行了徹底替換的,其他的設施是在逐漸縮容的過程,還會共存一段時間。
(豆瓣數據平臺架構)
JuiceFS 作為統一存儲數據平臺
為了更好地滿足不同的 I/O 需求和安全性考慮,我們會為不同的使用場景創建不同的 JuiceFS 卷,并進行不同的配置。JuiceFS 相對于之前的 MooseFS,創建文件系統更加簡單,實現了按需創建。除了 SQL 數據平臺外,我們的使用場景基本上都是由 JuiceFS 提供的服務。
在 JuiceFS 中,數據有幾種類型:在線讀寫、在線讀取離線寫入、在線寫入離線讀取、離線讀寫。
所有的讀寫類型都在 JuiceFS 上進行,比如日志匯聚到卷中,Spark 可能會讀取并進行 ETL,然后將數據寫入數據湖。此外,從 Kafka 數據源讀取的數據也會通過 Spark 進行處理并寫入數據湖。
Spark 的 Check Point 直接存儲在另一個 JuiceFS 卷中,而數據湖的數據則直接提供給算法組的同學進行模型訓練,并將訓練結果通過 JuiceFS 寫回。我們的運維團隊則通過各種腳本或工具來管理 JuiceFS 上的文件生命周期,包括是否對其進行歸檔處理等。因此,整個數據在 JuiceFS 中的流轉過程大致如上圖所示。
新數據平臺組件介紹
Debian based container
首先,運維團隊選擇了 Debian based container 作為基礎鏡像,我們就直接使用了。我們的計算平臺的鏡像很大,為了解決任務啟動速度的問題,團隊在每個節點上預拉取了鏡像。
JuiceFS
切換到 JuiceFS 存儲系統時,用戶感受不到變化,JuiceFS 非常穩定。JuiceFS 比 MooseFS 更好的一點是,它擁有 HDFS 的 SDK,方便了團隊將來切換到 Spark 等工具。團隊在 Kubernetes 上使用了 JuiceFS CSI,可以直接使用 JuiceFS 作為 Persist Volume,用起來十分方便。JuiceFS 團隊溝通高效,解決問題迅速。例如,當 stream 的 checkpoint 頻率太高時,JuiceFS 團隊早早通知并迅速解決。
Kubernentes
我們早在 1.10 版本的時候就開始試用 Kubernetes。后來豆瓣對外的服務集群在 1.12 版本開始逐步遷移到 Kubernetes,基本上是在現有機器上完成了原地的替換。計算集群則是在上云后開始搭建的,基于1.14 版本。我們在版本升級方面可能比其他公司更為激進,目前我們的 Kubernetes 版本已經升級到了1.26 版。
我們選擇 Kubernetes 作為計算平臺的原因之一是它有比較統一的組件。此外,通過 scheduling framework 或者 Volcano,我們可以影響它的調度,這是我們比較希望擁有的一個特性。
我們還可以利用社區的 Helm 非??焖俚夭渴鹨恍┬枰臇|西,比如 Airflow、Datahub 和 Milvus 等服務,這些服務都是通過 Helm 部署到我們的離線 Kubernetes 集群中提供的。
Spark
在最開始測試 Spark 時,我們像使用 Dpark 一樣將任務運行在 Mesos 集群上。之后我們選定了 Kubernetes,使用 Google Cloud Platform 上的 spark-on-k8s-operator 將 Spark 任務部署到 Kubernetes 集群中,并部署了兩個 Streaming 任務,但并未進行大規模的部署。
隨后,我們確定了使用 Kubernetes 和 Airflow,計劃自己實現一個 Airflow Operator,在 Kubernetes 中直接提交 Spark 任務,并使用 Spark 的 Cluster Mode 將任務提交到 Kubernetes 集群中。
對于開發環境,我們使用 JupyterLab 進行開發。廠內有一個 Python 庫對 Spark Session 進行了一些小的預定義配置,以確保 Spark 任務能夠直接提交到 Kubernetes 集群上。
目前,我們使用 Kubernetes Deployment 直接部署 Streaming 任務,這是一個很簡單的狀態,未來可能會有一些改進的地方。另外,我們正在準備試用 Kyuubi & Spark Connect 項目,希望能夠為線上任務提供更好的讀寫離線數據的體驗。
我們的版本升級非常激進,但確實從社區中獲益匪淺。我們解決了日常計算任務中許多常見的優化場景。我們激進升級的原因是希望能夠盡可能多地利用社區的資源,提供新特性給開發者。但我們也遇到了問題,例如 Spark 3.2 的 parquet zstd 壓縮存在內存泄漏。為了規避這個問題,我們提前引入了未發布的補丁。
現在,我們使用兩種方式來讀寫 JuiceFS 數據:FUSE 和 HDFS。FUSE 主要用于 ETL 任務,例如讀寫日志和 CSV 文件。我們也會將 Hive 表轉存為 CSV 文件下載供未切換到 Spark 的任務進行計算。其他的數據,則直接通過預先配置好的 HDFS(如 Hive Table 和 Iceberg Table)進行讀寫,這大大簡化了我們的工作。
在數據湖的選擇上,我們一開始考慮了 Delta Lake,但由于它不支持 Merge on Read,在目前的使用場景存在寫放大,我們放棄了它。取而代之,我們選擇了 Iceberg,并將其用于 MySQL CDC 處理。我們將數據直接存儲在 JuiceFS 上進行讀寫,并且目前沒有遇到任何性能上的問題。未來,如果我們需要擴大規模使用,可能需要與 JuiceFS 的團隊溝通一下,看看有哪些優化措施。
04 收獲與展望
我們切換到新的計算平臺之后,獲得了很多原來沒有的功能。例如,我們現在可以使用基于 SQL 的大量任務,這些任務的性能比以前好得多,各種報表的實時性也更好了。
與 Mesos 的情況不同,Spark 聲明了多少資源就使用多少資源,這與以前的 Dpark 相比有很大的差異,因為以前大家都是公平分享,相互之間會有影響?,F在,每個任務的執行時間都比較可預測,任務評估也比較容易預測,整個新平臺對于業務數據的讀取也有更好的時效性。
以前的歷史包袱是相當沉重的,現在我們已經趕上了社區的步伐。去年年末的各種統計和排名都已經遷移到了新的計算平臺上,并且運行非常穩定。
我們正在優先考慮采取一些成本下降措施,以實現整個計算集群的動態擴縮容。我們正積極努力實現此目標,并希望提供更加穩定的 SQL 接口。為此,我們計劃采用支持 Multi-tenant 的 SQL 服務器,并嘗試引入 Spark 3.4 的最新特性。
長遠來看,我們希望通過 Spark Remote Shuffle Service 進一步實現存算分離,以便更有效地利用資源。也許未來我們會開發一個“Spark as a Service”,提供給開發者使用。總之,我們正在追趕社區的步伐,并不斷努力提升我們的技術水平。
-
數據存儲
+關注
關注
5文章
983瀏覽量
51056 -
SQL
+關注
關注
1文章
774瀏覽量
44250 -
分布式
+關注
關注
1文章
924瀏覽量
74610
原文標題:從本地到云端:豆瓣如何使用JuiceFS實現統一的數據存儲
文章出處:【微信號:OSC開源社區,微信公眾號:OSC開源社區】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論