今天的案例分享來(lái)自社區(qū)用戶一面數(shù)據(jù),這是一家通過(guò)解讀電商平臺(tái)和社交媒體渠道的海量數(shù)據(jù),為全球快消巨頭(如寶潔、聯(lián)合利華和瑪氏等)提供實(shí)時(shí)、全面的數(shù)據(jù)洞察的公司。
在去年的案例中,一面分享了架構(gòu)設(shè)計(jì)和實(shí)踐。本次案例,進(jìn)一步補(bǔ)充了在后續(xù)數(shù)據(jù)遷移過(guò)程中一面遇到的具體挑戰(zhàn)以及分級(jí)存儲(chǔ)的實(shí)踐。如果你正在考慮將 Hadoop 遷移到云上,這篇文章從架構(gòu)設(shè)計(jì)到實(shí)際操作都涵蓋了豐富的內(nèi)容,是一篇不容錯(cuò)過(guò)的案例。
一面數(shù)據(jù)原有的技術(shù)架構(gòu)是在線下機(jī)房中使用 CDH 構(gòu)建的大數(shù)據(jù)集群。自公司成立以來(lái),每年都保持著高速增長(zhǎng),業(yè)務(wù)的增長(zhǎng)帶來(lái)了數(shù)據(jù)量的劇增。
在過(guò)去幾年中,我們按照每 1 到 2 年的規(guī)劃擴(kuò)容硬件,但往往在半年之后就不得不再次擴(kuò)容。而每次擴(kuò)容都需要花費(fèi)大量精力。
為了解決包括擴(kuò)容周期長(zhǎng)、計(jì)算存儲(chǔ)資源不匹配以及高昂的運(yùn)維成本等這些問(wèn)題,我們決定對(duì)數(shù)據(jù)架構(gòu)進(jìn)行改造,并將數(shù)據(jù)遷移到云端,采用存算分離的結(jié)構(gòu)。 在這個(gè)案例中,我們將為大家介紹 Hadoop 上云的架構(gòu)設(shè)計(jì)、選型的思考、組件評(píng)估以及數(shù)據(jù)遷移的整個(gè)過(guò)程。
目前,基于 JuiceFS 我們實(shí)現(xiàn)了計(jì)算和存儲(chǔ)分離的架構(gòu),總存儲(chǔ)量增加了 2 倍;性能方面的變化無(wú)明顯感知,運(yùn)維成本大幅降低。在案例的末尾還附上了針對(duì)阿里云 EMR 以及 JuiceFS 的一手運(yùn)維經(jīng)驗(yàn),希望這個(gè)案例能為其他面臨類似問(wèn)題的同行提供有價(jià)值的參考。
舊架構(gòu)及挑戰(zhàn)
為了滿足業(yè)務(wù)需求,一面數(shù)據(jù)抓取了國(guó)內(nèi)外數(shù)百個(gè)大型網(wǎng)站的數(shù)據(jù),目前數(shù)量已經(jīng)超過(guò) 500 個(gè),并積累了大量的原始數(shù)據(jù)、中間數(shù)據(jù)和結(jié)果數(shù)據(jù)。隨著我們不斷增加抓取的網(wǎng)站數(shù)量和服務(wù)的客戶群,數(shù)據(jù)量也在快速增長(zhǎng)。因此,我們著手開(kāi)始進(jìn)行擴(kuò)容以滿足需求的增長(zhǎng)。
原有的架構(gòu)是在一個(gè)線下機(jī)房使用 CDH 構(gòu)建了一個(gè)大數(shù)據(jù)集群。如下圖所示,我們主要使用了 Hive、Spark 和 HDFS 等組件。在 CDH 的上游有多種數(shù)據(jù)生產(chǎn)系統(tǒng),在這里只列出了 Kafka,因?yàn)榕c JuiceFS 相關(guān);除了 Kafka 之外,還有其他一些存儲(chǔ)方式,包括 TiDB、HBase、MySQL 等等。
一面數(shù)據(jù)原有數(shù)據(jù)架構(gòu)
數(shù)據(jù)流向方面,我們有一個(gè)上游的業(yè)務(wù)系統(tǒng)和數(shù)據(jù)采集系統(tǒng),數(shù)據(jù)會(huì)被采集下來(lái)后寫入 Kafka。然后我們使用一個(gè) Kafka Connect 集群,將數(shù)據(jù)同步到 HDFS。
在這個(gè)架構(gòu)上方,我們使用了一個(gè)自研的數(shù)據(jù)開(kāi)發(fā)平臺(tái),稱為 OneWork,用于開(kāi)發(fā)和管理各種任務(wù)。這些任務(wù)會(huì)通過(guò) Airflow 下發(fā)到任務(wù)隊(duì)列進(jìn)行調(diào)度。
挑戰(zhàn)
業(yè)務(wù) / 數(shù)據(jù)會(huì)增長(zhǎng)比較快,業(yè)務(wù)擴(kuò)容周期長(zhǎng)。公司在 2016 年線下機(jī)房部署了 CDH 集群,到 2021 年已存儲(chǔ)和處理 PB 級(jí)的數(shù)據(jù)。公司自創(chuàng)立以來(lái)一直保持每年翻一番的高增長(zhǎng),而比業(yè)務(wù)量增長(zhǎng)更快的是 Hadoop 集群的數(shù)據(jù)量。
在這幾年間,按 1 到 2 年規(guī)劃的硬件,往往因數(shù)據(jù)增長(zhǎng)超出預(yù)期而在半年后不得不再次擴(kuò)容。每次擴(kuò)容周期可達(dá)到一個(gè)月,除了花費(fèi)大量精力跟進(jìn)行政和技術(shù)流程,業(yè)務(wù)端也不得不安排較多人日控制數(shù)據(jù)量。如果選擇購(gòu)買硬盤和服務(wù)器來(lái)進(jìn)行擴(kuò)容,實(shí)施周期會(huì)相對(duì)較長(zhǎng)。
存儲(chǔ)計(jì)算耦合,容量規(guī)劃難,容易錯(cuò)配。 傳統(tǒng)的 Hadoop 架構(gòu)中,存儲(chǔ)和計(jì)算是緊密耦合的,難以根據(jù)存儲(chǔ)或計(jì)算的需求獨(dú)立進(jìn)行擴(kuò)容和規(guī)劃。舉個(gè)例子,假設(shè)我們需要擴(kuò)容存儲(chǔ),于是首先需要購(gòu)買一批新的硬盤,同時(shí)連帶著需要購(gòu)買計(jì)算資源。在最初時(shí),計(jì)算資源可能會(huì)變得過(guò)剩,因?yàn)榭赡軐?shí)際不需要那么多的計(jì)算資源,從而一定程度上導(dǎo)致了超前投資。
CDH 版本比較老,不敢升級(jí)。 我們因?yàn)榧阂步ǖ谋容^早了,為了穩(wěn)定,也就不敢升級(jí)了。
運(yùn)維成本較高(全公司僅 1 個(gè)全職運(yùn)維)公司當(dāng)時(shí)有 200 多個(gè)人,只有一個(gè)運(yùn)維,這意味著運(yùn)維工作的工作量很大。因此,我們希望能夠采用更穩(wěn)定、更簡(jiǎn)單的架構(gòu)來(lái)提供支持。
機(jī)房存在單點(diǎn)風(fēng)險(xiǎn)。考慮到長(zhǎng)遠(yuǎn)的因素,所有的數(shù)據(jù)都存儲(chǔ)在同一個(gè)機(jī)房中,這存在一定的風(fēng)險(xiǎn)。例如,如果光纜被挖斷,這種情況經(jīng)常發(fā)生,那么我們僅有一個(gè)機(jī)房仍然會(huì)面臨單點(diǎn)故障的風(fēng)險(xiǎn)。
新架構(gòu)與選型 選型考量
考慮到這些因素和挑戰(zhàn),我們決定進(jìn)行一些新的改變。以下是我們考慮架構(gòu)升級(jí)的一些主要維度:
上云,彈性伸縮,靈活運(yùn)維。利用云上的服務(wù)可以簡(jiǎn)化運(yùn)維工作。例如,在存儲(chǔ)方面,盡管 HDFS 本身是一個(gè)穩(wěn)定且成熟的解決方案,但我們更愿意將時(shí)間投入到業(yè)務(wù)層面上,而不是底層的運(yùn)維工作。因此,使用云服務(wù)可能更加簡(jiǎn)單。此外,通過(guò)利用云上的資源,我們可以實(shí)現(xiàn)彈性伸縮,無(wú)需等待長(zhǎng)時(shí)間的硬件部署和系統(tǒng)配置周期。
存儲(chǔ)計(jì)算分離。我們希望將存儲(chǔ)和計(jì)算解耦,以實(shí)現(xiàn)更好的靈活性和性能。
盡量使用開(kāi)源組件,避免云廠商綁定。盡管我們選擇上云,但我們不希望過(guò)于依賴云服務(wù)本身。我們?cè)跒榭蛻籼峁┓?wù)時(shí)會(huì)使用云原生的解決方案,例如使用 AWS Redshift 等,但我們?cè)谧陨順I(yè)務(wù)方面更傾向于使用開(kāi)源組件。
盡可能與現(xiàn)有方案兼容,控制改動(dòng)成本和風(fēng)險(xiǎn)。我們希望新架構(gòu)與現(xiàn)有解決方案兼容,以避免引入額外的開(kāi)發(fā)成本,并對(duì)我們的業(yè)務(wù)產(chǎn)生影響。
新架構(gòu):阿里云 EMR + OSS + JuiceFS
最終選擇的方案是使用“阿里云 EMR + JuiceFS + 阿里云 OSS” 來(lái)搭建存算分離的大數(shù)據(jù)平臺(tái),將云下數(shù)據(jù)中心的業(yè)務(wù)逐步遷移上云。
這個(gè)架構(gòu)使用對(duì)象存儲(chǔ)來(lái)替代 HDFS,并選擇了 JuiceFS 作為協(xié)議層,因?yàn)?JuiceFS 兼容 POSIX 和 HDFS 協(xié)議。在頂部,我們使用了云上半托管的 Hadoop 解決方案 EMR。它包含了很多 Hadoop 相關(guān)的組件,例如 Hive、Impala、Spark、Presto/Trino 等等。
一面數(shù)據(jù)架構(gòu)圖
阿里云 vs 其他公有云
首先是決定使用哪家云廠商。由于業(yè)務(wù)需求,AWS、Azure 和阿里云都有在用,綜合考慮后認(rèn)為阿里云最適合,有這些因素:
物理距離:阿里云在我們線下機(jī)房同城有可用區(qū),網(wǎng)絡(luò)專線的延遲小,成本低
開(kāi)源組件齊全:阿里云 EMR 上包含的開(kāi)源組件很多很全,除了我們重度使用的 Hive、Impala、Spark、Hue,也能方便集成 Presto、Hudi、Iceberg 等。我們?cè)谡{(diào)研時(shí)發(fā)現(xiàn)只有阿里云 EMR 自帶了 Impala,AWS 和 Azure 要么版本低,要么要自己安裝部署。
JuiceFS vs JindoFS
阿里云的 EMR 本身也有使用 JindoFS 的存算分離方案,但基于以下考慮,我們最終選擇了 JuiceFS:
JuiceFS 使用 Redis 和對(duì)象存儲(chǔ)為底層存儲(chǔ),客戶端完全是無(wú)狀態(tài)的,可以在不同環(huán)境訪問(wèn)同一個(gè)文件系統(tǒng),提高了方案的靈活性。而 JindoFS 元數(shù)據(jù)存儲(chǔ)在 EMR 集群的本地硬盤,不便于維護(hù)、升級(jí)和遷移。
JuiceFS 的存儲(chǔ)方案豐富,而且支持不同方案的在線遷移,提高了方案的可移植性。JindoFS 塊數(shù)據(jù)只支持 OSS.
JuiceFS 以開(kāi)源社區(qū)為基礎(chǔ),支持所有公有云環(huán)境,方便后期擴(kuò)展到多云架構(gòu)。
關(guān)于 JuiceFS
直接截取官方文檔[1] 的介紹:
JuiceFS 是一款面向云原生設(shè)計(jì)的高性能共享文件系統(tǒng),在 Apache 2.0 開(kāi)源協(xié)議下發(fā)布。提供完備的 POSIX[2] 兼容性,可將幾乎所有對(duì)象存儲(chǔ)接入本地作為海量本地磁盤使用,亦可同時(shí)在跨平臺(tái)、跨地區(qū)的不同主機(jī)上掛載讀寫。
JuiceFS 采用「數(shù)據(jù)」與「元數(shù)據(jù)」分離存儲(chǔ)的架構(gòu),從而實(shí)現(xiàn)文件系統(tǒng)的分布式設(shè)計(jì)。使用 JuiceFS 存儲(chǔ)數(shù)據(jù),數(shù)據(jù)本身會(huì)被持久化在對(duì)象存儲(chǔ)[3](例如,Amazon S3),相對(duì)應(yīng)的元數(shù)據(jù)可以按需持久化在 Redis、MySQL、TiKV、SQLite 等多種數(shù)據(jù)庫(kù)[4] 中。
除了 POSIX 之外,JuiceFS 完整兼容 HDFS SDK,與對(duì)象存儲(chǔ)結(jié)合使用可以完美替換 HDFS,實(shí)現(xiàn)存儲(chǔ)和計(jì)算分離。
JuiceFS 架構(gòu)圖
Hadoop 遷移云上 PoC 設(shè)計(jì)
PoC 的目的是快速驗(yàn)證方案的可行性,有幾個(gè)具體目標(biāo):
驗(yàn)證 EMR + JuiceFS + OSS 整體方案的可行性
檢查 Hive、Impala、Spark、Ranger 等組件版本的兼容性
評(píng)估對(duì)比性能表現(xiàn),用了 TPC-DS 的測(cè)試用例和部分內(nèi)部真實(shí)業(yè)務(wù)場(chǎng)景,沒(méi)有非常精確的對(duì)比,但能滿足業(yè)務(wù)需求
評(píng)估生產(chǎn)環(huán)境所需的節(jié)點(diǎn)實(shí)例類型和數(shù)量(算成本)
探索數(shù)據(jù)同步方案
探索驗(yàn)證集群與自研 ETL 平臺(tái)、Kafka Connect 等的集成方案
期間做了大量測(cè)試、文檔調(diào)研、內(nèi)外部(阿里云 + JuiceFS 團(tuán)隊(duì))討論、源碼理解、工具適配等工作,最終決定繼續(xù)推進(jìn)。
實(shí)施
我們?cè)?2021 年 10 月開(kāi)始探索 Hadoop 的上云方案;11 月做了大量調(diào)研和討論,基本確定方案內(nèi)容;12 月和 2022 年 1 月春節(jié)前做了 PoC 測(cè)試,在春節(jié)后 3 月份開(kāi)始搭建正式環(huán)境并安排遷移。為了避免導(dǎo)致業(yè)務(wù)中斷,整個(gè)遷移過(guò)程以相對(duì)較慢的節(jié)奏分階段執(zhí)行, 遷移完后,云上的 EMR 集群數(shù)據(jù)量預(yù)計(jì)會(huì)超過(guò)單副本 1 PB。
整體架構(gòu)設(shè)計(jì)
做完技術(shù)選型之后,架構(gòu)設(shè)計(jì)也能很快確定下來(lái)。考慮到除了 部分業(yè)務(wù)仍然會(huì)保留在數(shù)據(jù)中心的 Hadoop 集群,所以整體實(shí)際上是個(gè)混合云的架構(gòu)。
整體架構(gòu)大致如上圖所示:左側(cè)是的線下機(jī)房,使用了傳統(tǒng)的 CDH 架構(gòu)和一些 Kafka 集群。右側(cè)是部署在阿里云上的 EMR 集群。這兩部分通過(guò)一條高速專線進(jìn)行連接。頂部是 Airflow 和 OneWork,由于都支持支持分布式部署,因此可以輕松進(jìn)行水平擴(kuò)展。
數(shù)據(jù)遷移的挑戰(zhàn) 挑戰(zhàn) 1:Hadoop 2 升到 Hadoop 3
我們 CDH 版本比較老,也不敢升級(jí),但我們既然做了遷移,肯定還是希望新集群能夠升級(jí)到新版本。在遷移過(guò)程中,需要注意 HDFS 2 和 3 之間的差異,接口協(xié)議和文件格式有可能會(huì)發(fā)生變化。JuiceFS 完美兼容 HDFS 2 & 3,很好地應(yīng)對(duì)了這個(gè)挑戰(zhàn)。
挑戰(zhàn) 2:Spark 2 升級(jí)到 Spark 3
Spark 的一個(gè)升級(jí)對(duì)我們影響是比較大的,因?yàn)橛胁簧俨患嫒莸母隆_@就意味著原來(lái)在 Spark 2 上面寫的代碼需要完成修改才能適配到新的版本里面去。
挑戰(zhàn) 3:Hive on Spark 不支持 Spark 3
在機(jī)房環(huán)境中,默認(rèn)使用的是 CDH 自帶的 Hive on Spark,但當(dāng)時(shí) CDH 中的 Spark 版本只有 1.6。我們?cè)谠粕鲜褂玫氖?Spark 3,而 Hive on Spark 并不支持 Spark 3,這導(dǎo)致我們無(wú)法繼續(xù)使用 Hive on Spark 引擎。
經(jīng)過(guò)調(diào)研和測(cè)試,我們將 Hive on Spark 改為了 Hive on Tez。這個(gè)改動(dòng)相對(duì)來(lái)說(shuō)還比較容易,因?yàn)?Hive 本身對(duì)于不同的計(jì)算引擎提供了抽象和適配,所以對(duì)于我們的上層代碼改動(dòng)較小。Hive on Tez 在性能上可能略慢于 Spark。此外,我們也關(guān)注國(guó)內(nèi)網(wǎng)易開(kāi)源的一個(gè)新計(jì)算引擎 Kyuubi,它兼容 Hive,并提供了一些新特性。
挑戰(zhàn) 4:Hive 1 升級(jí)到 Hive 3,元數(shù)據(jù)結(jié)構(gòu)有變化
對(duì)于 Hive 升級(jí)來(lái)說(shuō),最主要的影響之一是元數(shù)據(jù)結(jié)構(gòu)的變化,因此在遷移過(guò)程中,我們需要進(jìn)行數(shù)據(jù)結(jié)構(gòu)的轉(zhuǎn)換。因?yàn)闊o(wú)法直接使用 Hive 來(lái)處理這種遷移,所以我們需要開(kāi)發(fā)相應(yīng)的程序來(lái)進(jìn)行數(shù)據(jù)結(jié)構(gòu)的轉(zhuǎn)換。
挑戰(zhàn) 5:權(quán)限管理由 Sentry 替換為 Ranger
這是一個(gè)比較小的問(wèn)題,就是我們之前使用 Sentry 做權(quán)限管理,這個(gè)社區(qū)不怎么活躍了,EMR 也沒(méi)有集成,所以就替換為 Ranger。
除了技術(shù)挑戰(zhàn)外,更大的挑戰(zhàn)來(lái)自與業(yè)務(wù)端。
業(yè)務(wù)挑戰(zhàn) 1:涉及的業(yè)務(wù)多,不能影響交付
我們擁有多個(gè)業(yè)務(wù),涉及不同的網(wǎng)站、客戶和項(xiàng)目。由于業(yè)務(wù)交付不能中斷,遷移過(guò)程必須進(jìn)行分業(yè)務(wù)處理,采用漸進(jìn)式遷移的方式。遷移過(guò)程中,數(shù)據(jù)的變動(dòng)會(huì)對(duì)公司的多個(gè)環(huán)節(jié)產(chǎn)生影響,例如 ETL 數(shù)據(jù)倉(cāng)庫(kù)、數(shù)據(jù)分析師、測(cè)試和產(chǎn)品開(kāi)發(fā)等。因此,我們需要進(jìn)行良好的溝通和協(xié)調(diào),制定項(xiàng)目管理計(jì)劃和排期。
業(yè)務(wù)挑戰(zhàn) 2:數(shù)據(jù)表、元數(shù)據(jù)、文件、代碼多
除了數(shù)據(jù),我們?cè)谏蠈舆€有許多業(yè)務(wù)代碼,包括數(shù)據(jù)倉(cāng)庫(kù)的代碼、ETL 的代碼以及一些應(yīng)用程序的代碼,如 BI 應(yīng)用需要查詢這些數(shù)據(jù)。
數(shù)據(jù)遷移:存量文件 & 增量文件
要遷移的數(shù)據(jù)包括兩部分:Hive Metastore 元數(shù)據(jù)以及 HDFS 上的文件。由于不能中斷業(yè)務(wù),采用存量同步 + 增量同步(雙寫)的方式進(jìn)行遷移;數(shù)據(jù)同步完后需要進(jìn)行一致性校驗(yàn)。
存量同步
對(duì)于存量文件同步,可以使用 JuiceFS 提供的功能完整的數(shù)據(jù)同步工具 sync 子命令[5] 來(lái)實(shí)現(xiàn)高效遷移。JuiceFS sync 命令支持單節(jié)點(diǎn)和多機(jī)并發(fā)同步,實(shí)際使用時(shí)發(fā)現(xiàn)單節(jié)點(diǎn)開(kāi)多線程即可打滿專線帶寬,CPU 和內(nèi)存占用低,性能表現(xiàn)非常不錯(cuò)。需要注意的是,同步過(guò)程中 sync 命令會(huì)在本地文件系統(tǒng)寫緩存,因此最好掛載到 SSD 盤來(lái)提升性能。
Hive Metastore 的數(shù)據(jù)同步則相對(duì)麻煩些:
兩個(gè) Hive 版本不一致,Metastore 的表結(jié)構(gòu)有差異,因此無(wú)法直接使用 MySQL 的導(dǎo)出導(dǎo)入功能
遷移后需要修改庫(kù)、表、分區(qū)存儲(chǔ)路徑(即 dbs 表的 DB_LOCATION_URI和 sds 表的 LOCATION)
因此我們開(kāi)發(fā)了一套腳本工具,支持表和分區(qū)粒度的數(shù)據(jù)同步,使用起來(lái)很方便。
增量同步
增量數(shù)據(jù)主要來(lái)自兩個(gè)場(chǎng)景:Kafka Connect HDFS Sink 和 ETL 程序,我們采用了雙寫機(jī)制。
Kafka Connect 的 Sink 任務(wù)都復(fù)制一份即可,配置方式上文有介紹。ETL 任務(wù)統(tǒng)一在 OneWork 上開(kāi)發(fā),底層使用 Airflow 進(jìn)行調(diào)度。通常只需要把相關(guān)的 DAG 復(fù)制一份,修改集群地址即可。實(shí)際遷移過(guò)程中,這一步遇到的問(wèn)題最多,花了大量時(shí)間來(lái)解決。主要原因是 Spark、Impala、Hive 組件版本的差異導(dǎo)致任務(wù)出錯(cuò)或數(shù)據(jù)不一致,需要修改業(yè)務(wù)代碼。這些問(wèn)題在 PoC 和早期的遷移中沒(méi)有覆蓋到,算是個(gè)教訓(xùn)。
數(shù)據(jù)校驗(yàn)
為了能讓業(yè)務(wù)放心的使用新的架構(gòu),數(shù)據(jù)校驗(yàn)必不可少。數(shù)據(jù)同步完后需要進(jìn)行一致性校驗(yàn),分三層:
文件一致。在存量同步階段做校驗(yàn),通常的方式是用 checksum. 最初的 JuiceFS sync 命令不支持 checksum 機(jī)制,我們建議和討論后,JuiceFS 團(tuán)隊(duì)很快就加上了該功能(issue,pull request[6])。除了 checksum,也可考慮使用文件屬性對(duì)比的方式:確保兩個(gè)文件系統(tǒng)里所有文件的數(shù)量、修改時(shí)間、屬性一致。比 checksum 的可靠性稍弱,但更輕量快捷。
元數(shù)據(jù)一致。有兩種思路:對(duì)比 Metastore 數(shù)據(jù)庫(kù)的數(shù)據(jù),或?qū)Ρ?Hive 的 DDL 命令的結(jié)果。
計(jì)算結(jié)果一致。即使用 Hive/Impala/Spark 跑一些查詢,對(duì)比兩邊的結(jié)果是否一致。一些可以參考的查詢:表 / 分區(qū)的行數(shù)、基于某個(gè)字段的排序結(jié)果、數(shù)值字段的最大 / 最小 / 平均值、業(yè)務(wù)中經(jīng)常使用的統(tǒng)計(jì)聚合等。
數(shù)據(jù)校驗(yàn)的功能也封裝到了腳本里,方便快速發(fā)現(xiàn)數(shù)據(jù)問(wèn)題。
分級(jí)存儲(chǔ)
遷移完業(yè)務(wù)穩(wěn)定運(yùn)行后,我們開(kāi)始考慮分級(jí)存儲(chǔ)。分級(jí)存儲(chǔ)在各種數(shù)據(jù)庫(kù)或存儲(chǔ)系統(tǒng)中都是一個(gè)常見(jiàn)問(wèn)題,數(shù)據(jù)存在冷熱區(qū)別,而存儲(chǔ)介質(zhì)的價(jià)格也存在差異,因此我們希望將冷數(shù)據(jù)存儲(chǔ)在更便宜的存儲(chǔ)介質(zhì)上以控制成本。
在之前的 HDFS 中,我們已經(jīng)實(shí)施了分級(jí)存儲(chǔ)策略,購(gòu)買了兩種類型的硬盤,將熱數(shù)據(jù)存儲(chǔ)在高速硬盤中,將冷數(shù)據(jù)存儲(chǔ)在低速硬盤中。
然而,JuiceFS 為了優(yōu)化性能采取的數(shù)據(jù)分塊模式,會(huì)對(duì)分級(jí)存儲(chǔ)帶來(lái)限制。按照 JuiceFS 的處理,當(dāng)文件存儲(chǔ)在對(duì)象存儲(chǔ)上時(shí),它被邏輯上拆分為許多 chunks、slices 和 blocks,最終以 block 的形式存儲(chǔ)在對(duì)象存儲(chǔ)中。
JuiceFS 數(shù)據(jù)分塊示意圖
因此,如果我們觀察對(duì)象存儲(chǔ)中的文件,實(shí)際上無(wú)法直接找到文件本身,而只能看到被分割成的小塊。即使 OSS 提供了聲明周期管理功能,但我們也無(wú)法基于表、分區(qū)或文件級(jí)別進(jìn)行生命周期的配置。
后續(xù)我們通過(guò)以下這種方式來(lái)解決。
兩個(gè) bucket:標(biāo)準(zhǔn)( JuiceFS ) + 低頻(OSS):創(chuàng)建兩個(gè)存儲(chǔ)桶,一個(gè)存儲(chǔ)桶用于 JuiceFS,并將所有數(shù)據(jù)存儲(chǔ)在標(biāo)準(zhǔn)存儲(chǔ)層中。另外,我們額外創(chuàng)建一個(gè)低頻的 OSS 存儲(chǔ)桶。
基于業(yè)務(wù)邏輯,對(duì)表 / 分區(qū) / 文件,配置存儲(chǔ)策略表。我們可以根據(jù)表、分區(qū)或文件來(lái)設(shè)置存儲(chǔ)策略,并編寫定時(shí)任務(wù)來(lái)掃描并執(zhí)行這些策略。
用 Juicesync 將低頻文件從 JuiceFS 導(dǎo)出到 OSS 并修改 Hive 元數(shù)據(jù)。文件從 JuiceFS 轉(zhuǎn)移到 OSS 之后會(huì)從 JuiceFS 刪除,并且在 OSS 上能看到完整的文件內(nèi)容,我們就可以對(duì)其設(shè)置生命周期規(guī)則。轉(zhuǎn)移完文件后需要及時(shí)修改 Hive 元數(shù)據(jù),,將 Hive 表或分區(qū)的位置更改為新的 OSS 地址。EMR 的 Hive/Impala/Spark 等組件原生支持 OSS,因此應(yīng)用層基本無(wú)感(需注意訪問(wèn)低頻文件會(huì)帶來(lái)額外開(kāi)銷)。
完成這個(gè)操作后,除了實(shí)現(xiàn)分級(jí)存儲(chǔ)以降低成本外,還有一個(gè)額外的好處是我們可以減少 JuiceFS 元數(shù)據(jù)的數(shù)量。因?yàn)檫@些文件不再屬于 JuiceFS,而是由 OSS 直接管理,這意味著 JuiceFS 中的 inode 數(shù)量會(huì)減少,元數(shù)據(jù)的管理壓力就會(huì)減輕,Redis 請(qǐng)求的數(shù)量和容量也會(huì)降低。從穩(wěn)定性的角度來(lái)看,這對(duì)系統(tǒng)會(huì)更有利。
架構(gòu)升級(jí)的收益 & 后續(xù)計(jì)劃 存算分離的收益
總的存儲(chǔ)量增長(zhǎng)了兩倍,計(jì)算資源不動(dòng),偶爾開(kāi)啟臨時(shí)的任務(wù)節(jié)點(diǎn)。在我們的場(chǎng)景中,數(shù)據(jù)量增長(zhǎng)非常快,但查詢需求相對(duì)穩(wěn)定。從 2021 年至今,數(shù)據(jù)量已增長(zhǎng)兩倍。計(jì)算資源在初始階段至今基本沒(méi)有做過(guò)太多的改動(dòng),除非出于某些業(yè)務(wù)需求需要更快的計(jì)算速度,我們會(huì)開(kāi)啟彈性資源和臨時(shí)任務(wù)節(jié)點(diǎn)來(lái)加速。
性能變化
總體無(wú)明顯感知,PoC 期間做過(guò)簡(jiǎn)單的 TPCDS 測(cè)試顯示差異不大,ad-hoc 的 Impala 查詢響應(yīng)變快了
影響因素多:HDFS -> JuiceFS、組件版本升級(jí)、Hive 計(jì)算引擎變化、集群負(fù)載等
在我們的業(yè)務(wù)場(chǎng)景中,主要是進(jìn)行大數(shù)據(jù)的批處理離線計(jì)算,總體而言對(duì)于性能的延遲并不敏感。
在 PoC 期間,我們進(jìn)行了一些簡(jiǎn)單的測(cè)試。然而,這些測(cè)試很難準(zhǔn)確說(shuō)明問(wèn)題,因?yàn)闇y(cè)試過(guò)程受到了許多影響因素的影響。我們首先更換了存儲(chǔ)系統(tǒng),從 HDFS 切換到了 JuiceFS,同時(shí)進(jìn)行了組件版本升級(jí),Hive 引擎也發(fā)生了變化。此外,集群負(fù)載也無(wú)法完全一致。在我們的場(chǎng)景中,與之前在物理服務(wù)器上部署的 CDH 相比,集群架構(gòu)的性能差異并不明顯。
易用性 & 穩(wěn)定性
JuiceFS 本身沒(méi)出過(guò)問(wèn)題
EMR 的使用有遇到些小問(wèn)題,總體上 CDH 更穩(wěn)定易用
實(shí)施復(fù)雜度
我們的場(chǎng)景里, 增量雙寫 & 數(shù)據(jù)校驗(yàn)過(guò)程花的時(shí)間最多(回過(guò)頭看校驗(yàn)的投入過(guò)大,可以精簡(jiǎn)) ;
影響因素多:跟業(yè)務(wù)場(chǎng)景(離線 / 實(shí)時(shí)、表 / 任務(wù)數(shù)量、上層應(yīng)用)、組件版本、配套工具和儲(chǔ)備。
當(dāng)評(píng)估類似架構(gòu)或方案的復(fù)雜度時(shí),有許多影響因素需要考慮。其中包括業(yè)務(wù)場(chǎng)景的差異,以及對(duì)延遲要求的敏感程度不同。此外,表數(shù)據(jù)量的規(guī)模也會(huì)產(chǎn)生影響。在我們的場(chǎng)景中,我們有大量的表和數(shù)據(jù)庫(kù),文件數(shù)量相對(duì)較多。此外,上層應(yīng)用程序的特性、使用業(yè)務(wù)的數(shù)量以及相關(guān)程序等也會(huì)對(duì)復(fù)雜度產(chǎn)生影響。另一個(gè)重要的影響因素是版本遷移的逐漸差異。如果只進(jìn)行平移而保持版本不變,那么組件的影響基本上可以消除。
配套工具和儲(chǔ)備是一個(gè)重要的影響因素。在進(jìn)行數(shù)倉(cāng)或 ETL 任務(wù)時(shí),有多種實(shí)現(xiàn)方式可供選擇,例如手動(dòng)編寫 Hive SQL 文件、Python 或 Java 程序,或者使用常見(jiàn)的調(diào)度工具。但無(wú)論采用哪種方式,我們都需要復(fù)制和修改這些程序,因?yàn)殡p寫是必要的。
我們使用自研的開(kāi)發(fā)平臺(tái) OneWork,在任務(wù)配置方面非常完善。通過(guò) OneWork 平臺(tái),用戶可以在 Web 界面上配置這些任務(wù),從而實(shí)現(xiàn)統(tǒng)一管理。Spark 任務(wù)的部署也無(wú)需登錄到服務(wù)器上操作,OneWork 會(huì)自動(dòng)提交到 Yarn 集群。這個(gè)平臺(tái)大大簡(jiǎn)化了代碼配置和修改的過(guò)程。我們編寫了一個(gè)腳本將任務(wù)配置復(fù)制出來(lái),進(jìn)行一些修改,就可以實(shí)現(xiàn)高度的自動(dòng)化程度,幾乎達(dá)到百分之八九十,從而順利運(yùn)行這些任務(wù)。
后續(xù)計(jì)劃大致有幾個(gè)方向:
繼續(xù)完成剩余業(yè)務(wù)的上云遷移;
探索 JuiceFS + OSS 的冷熱分級(jí)存儲(chǔ)策略。JuiceFS 的文件在 OSS 上完全被打散,無(wú)法基于文件級(jí)別做分級(jí)。目前的思路是將冷數(shù)據(jù)從 JuiceFS 遷移到 OSS 上,設(shè)置為歸檔存儲(chǔ),修改 Hive 表或分區(qū)的 LOCATION,不影響使用;
目前 JuiceFS 使用 Redis 作為元數(shù)據(jù)引擎,假如將來(lái)數(shù)據(jù)量增加,使用 Redis 有壓力的話可能考慮切換為 TiKV 或其他引擎;
探索 EMR 的彈性計(jì)算實(shí)例,爭(zhēng)取能在滿足業(yè)務(wù) SLA 的前提下降低使用成本。
附錄 部署和配置 關(guān)于 IDC- 阿里云專線:
能提供專線服務(wù)的供應(yīng)商很多,包括 IDC、阿里云、運(yùn)營(yíng)商等,選擇的時(shí)候主要考慮線路質(zhì)量、成本、施工周期等因素,最終我們選擇了 IDC 的方案。IDC 跟阿里云有合作,很快就完成了專線的開(kāi)通。這方面如果遇到問(wèn)題,可以找 IDC 和阿里云的支持。除專線租用成本,阿里云也會(huì)收取下行(從阿里云到 IDC)方向傳輸費(fèi)用。專線兩端的內(nèi)網(wǎng) IP 完全互通,阿里云和 IDC 兩側(cè)都需要一些路由配置。
關(guān)于 EMR Core/Task 節(jié)點(diǎn)類型的選擇:
JuiceFS 可以使用本地硬盤做緩存[7],能進(jìn)一步減少 OSS 帶寬需求并提高 EMR 性能。更大的本地存儲(chǔ)空間,可以提供更高的緩存命中率。
阿里云本地 SSD 實(shí)例是較高性價(jià)比的 SSD 存儲(chǔ)方案(相對(duì)于云盤),用作緩存正合適。JuiceFS 社區(qū)版未支持分布式緩存,意味著每一個(gè)節(jié)點(diǎn)都需要一個(gè)緩存池,所以應(yīng)該選用盡量大的節(jié)點(diǎn)。
基于以上考慮和配置對(duì)比,我們決定選用 ecs.i2.16xlarge,每個(gè)節(jié)點(diǎn) 64 vCore、512GiB Memory、1.8T*8 SSD。
關(guān)于 EMR 版本:
軟件方面,主要包括確定組件版本、開(kāi)啟集群、修改配置。我們機(jī)房使用的是 CDH 5.14,其中 Hadoop 版本是 2.6,阿里云上最接近的版本是 EMR 3.38. 但調(diào)研時(shí)發(fā)現(xiàn)該版本的 Impala 和 Ranger 不兼容(實(shí)際上我們機(jī)房使用的是 Sentry 做權(quán)限管理,但 EMR 上沒(méi)有),最終經(jīng)過(guò)評(píng)估對(duì)比,決定直接使用 EMR 5 的最新版,幾乎所有組件的大版本都做了升級(jí)(包含 Hadoop 3、Spark 3 和 Impala 3.4)。此外,使用外部 MySQL 作為 Hive Metastore、Hue、Ranger 的數(shù)據(jù)庫(kù)。
關(guān)于 JuiceFS 配置:
基本參考 JuiceFS 官方文檔《在 Hadoop 中通過(guò) Java 客戶端訪問(wèn) JuiceFS[8]》即可完成配置。另外我們也配置了這些參數(shù):
緩存相關(guān):其中最重要的是 juicefs.cache-dir 緩存目錄。這個(gè)參數(shù)支持通配符,對(duì)多個(gè)硬盤的實(shí)例環(huán)境很友好,如設(shè)置為/mnt/disk*/juicefs-cache(需要手動(dòng)創(chuàng)建目錄,或在 EMR 節(jié)點(diǎn)初始腳本中創(chuàng)建),即用全部本地 SSD 作為緩存。另外也要關(guān)注 juicefs.cache-size、juicefs.free-space 兩個(gè)參數(shù)。
juicefs.push-gateway:設(shè)置一個(gè) Prometheus Push Gateway,用于采集 JuiceFS Java 客戶端的指標(biāo)。
juicefs.users、juicefs.groups:分別設(shè)置為 JuiceFS 中的一個(gè)文件(如 jfs://emr/etc/users、jfs://emr/etc/groups),解決多個(gè)節(jié)點(diǎn) uid 和 gid 可能不統(tǒng)一的問(wèn)題。
關(guān)于 Kafka Connect 使用 JuiceFS:
經(jīng)過(guò)一些測(cè)試,確認(rèn) JuiceFS 可以完美應(yīng)用于 Kafka Connect 的 HDFS Sink 插件(我們把配置方式也補(bǔ)充到了官方文檔[9])。相比使用 HDFS Sink 寫入 HDFS,寫入 JuiceFS 需要增加或修改以下配置項(xiàng):
將 JuiceFS Java SDK 的 JAR 包發(fā)布到 Kafka Connect 每一個(gè)節(jié)點(diǎn)的 HDFS Sink 插件目錄。Confluent 平臺(tái)的插件路徑是:/usr/share/java/confluentinc-kafka-connect-hdfs/lib
編寫包含 JuiceFS 配置的 core-site.xml,發(fā)布到 Kafka Connect 每一個(gè)節(jié)點(diǎn)的任意目錄。包括這些必須配置的項(xiàng)目:
fs.jfs.impl = io.juicefs.JuiceFileSystem fs.AbstractFileSystem.jfs.impl = io.juicefs.JuiceFS juicefs.meta = redis://:password@my.redis.com:6379/1
請(qǐng)參見(jiàn) JuiceFS Java SDK 的配置文檔。
Kafka Connector 任務(wù)設(shè)置:
hadoop.conf.dir=一手運(yùn)維經(jīng)驗(yàn)store.url=jfs:// /<路徑>
在整個(gè)實(shí)施過(guò)程中陸陸續(xù)續(xù)踩了一些坑,積累了一些經(jīng)驗(yàn),分享給大家做參考。
阿里云 EMR 和組件相關(guān)
兼容性
EMR 5 的 Hive 和 Spark 版本不兼容,無(wú)法使用 Hive on Spark,可以把默認(rèn)的引擎改成 Hive on Tez.
Impala 的 stats 數(shù)據(jù)從舊版同步到新版后,可能因?yàn)?IMPALA-10230[10] 導(dǎo)致表無(wú)法查詢。解決方案是在同步元數(shù)據(jù)時(shí),將 num_nulls=-1 的改成 num_nulls=0. 可能需要用到 CatalogObjects.thrift[11] 文件。
原集群有少量 Textfile 格式的文件用了 snappy 壓縮,新版 Impala 無(wú)法讀取,報(bào)錯(cuò) Snappy: RawUncompress failed,可能是 IMPALA-10005[12] 導(dǎo)致的。規(guī)避方案是不要對(duì) Textfile 文件使用 snappy 壓縮。
Impala 3.4 相比 2.11 的 CONCAT_WS 函數(shù)行為有差異,老版本 CONCAT_WS('_', 'abc', NULL) 會(huì)返回 NULL,而新版本返回 'abc'.
Impala 3.4 對(duì) SQL 中的保留關(guān)鍵字引用更嚴(yán)格,必須加上 “''”. 其實(shí)一個(gè)好習(xí)慣是業(yè)務(wù)代碼不要使用保留關(guān)鍵字。
PoC 或前期測(cè)試的覆蓋度盡可能完整,用真實(shí)的業(yè)務(wù)代碼去跑。我們?cè)?PoC 和早期遷移的業(yè)務(wù)中用到的組件特性比較少,基本都是最常用、保持兼容的功能,因此比較順利。但在第二批遷移過(guò)程中就暴露出了很多問(wèn)題,雖然最終都有解決,但花了很多額外的時(shí)間去做診斷和定位,打亂了節(jié)奏。
性能
EMR 5 的 Impala 3.4 打了 IMPALA-10695[13] 這個(gè)補(bǔ)丁,支持對(duì) oss:// 和 jfs://(本意是支持 JindoFS,但 JuiceFS 也默認(rèn)使用 jfs 這個(gè) scheme)設(shè)置獨(dú)立的 IO 線程數(shù)。在 EMR 控制臺(tái)上增加或修改 Impala 的配置項(xiàng) num_oss_io_threads.
阿里云 OSS 有賬號(hào)級(jí)別的帶寬限制,默認(rèn) 10Gbps,隨著業(yè)務(wù)規(guī)模上升容易成為瓶頸。可以與阿里云溝通調(diào)整。
運(yùn)維
EMR 可以關(guān)聯(lián)一個(gè) Gateway 集群,通常用來(lái)部署業(yè)務(wù)程序。如果要在 Gateway 上用 client 模式提交 Spark 任務(wù),需要先將 Gateway 機(jī)器的 IP 加到 EMR 節(jié)點(diǎn)的 hosts 文件。默認(rèn)可以使用 cluster 模式。
EMR 5 會(huì)開(kāi)啟一個(gè) Spark ThriftServer,在 Hue 上可以直接寫 Spark SQL,用起來(lái)很方便。但默認(rèn)配置有個(gè)坑,會(huì)寫大量日志(路徑大概是 /mnt/disk1/log/spark/spark-hadoop-org.apache.spark.sql.hive.thriftserver.HiveThriftServer2-1-emr-header-1.cluster-xxxxxx.out),導(dǎo)致硬盤寫滿。解決方案有兩個(gè):配置 log rotate 或把 spark.driver.extraJavaOptions 配置清空(阿里云技術(shù)支持的建議)。
JuiceFS 相關(guān)
JuiceFS 需要每個(gè)節(jié)點(diǎn)上具有相同的 UID 和 GID,否則很容易出現(xiàn)權(quán)限問(wèn)題。有兩種實(shí)現(xiàn)方式:修改操作系統(tǒng)的用戶[14](比較適合新機(jī)器,沒(méi)有歷史包袱),或者在 JuiceFS 上維護(hù)一個(gè)用戶映射表[15]。我們之前也分享過(guò)一篇 JuiceFS + HDFS 權(quán)限問(wèn)題定位[16],有詳細(xì)討論。通常需要維護(hù)映射的用戶有 impala, hive, hadoop 等。如果使用 Confluent Platform 搭建 Kafka Connect,也需要配置 cp-kafka-connect 用戶。
使用默認(rèn)的 JuiceFS IO 配置[17] 時(shí),相同的寫查詢,Hive on Tez 和 Spark 都比 Impala 快很多(但在機(jī)房里 Impala 更快)。最終發(fā)現(xiàn)將 juicefs.memory-size 從默認(rèn)的 300 (MiB) 改成 1024 之后 Impala 的寫入性能有成倍的提升。
在做 JuiceFS 的問(wèn)題診斷和分析時(shí),客戶端日志很有用,需要注意 POSIX 和 Java SDK 的日志是不一樣的,詳見(jiàn) JuiceFS 故障診斷和分析 | JuiceFS Document Center[18]
注意監(jiān)控 Redis 的空間用量,Redis 如果滿了,整個(gè) JuiceFS 集群無(wú)法寫入。(這點(diǎn)需要特別注意) 使用 JuiceFS sync 把機(jī)房數(shù)據(jù)往云上同步時(shí),選擇在有 SSD 的機(jī)器上跑,獲得更好的性能。
審核編輯:劉清
-
存儲(chǔ)器
+關(guān)注
關(guān)注
38文章
7455瀏覽量
163621 -
MYSQL數(shù)據(jù)庫(kù)
+關(guān)注
關(guān)注
0文章
95瀏覽量
9383 -
tpc
+關(guān)注
關(guān)注
0文章
15瀏覽量
10529 -
HDFS
+關(guān)注
關(guān)注
1文章
30瀏覽量
9570 -
AWS
+關(guān)注
關(guān)注
0文章
427瀏覽量
24315
原文標(biāo)題:Hadoop 上云: 存算分離架構(gòu)設(shè)計(jì)與遷移實(shí)踐
文章出處:【微信號(hào):AI前線,微信公眾號(hào):AI前線】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論