一面數據: Hadoop 遷移雲上架構設計與實踐
- 2022 年 7 月 28 日
- 筆記
背景
一面數據創立於 2014 年,是一家領先的數據智慧解決方案提供商,通過解讀來自電商平台和社交媒體渠道的海量數據,提供實時、全面的數據洞察。長期服務全球快消巨頭(寶潔、聯合利華、瑪氏等),獲得行業廣泛認可。公司與阿里、京東、位元組合作共建多個項目,旗下知乎數據專欄「數據冰山」擁有超30萬粉絲。一面所屬艾盛集團(Ascential)在倫敦證券交易所上市,在 120 多個國家為客戶提供本地化專業服務。
公司在 2016 年線下機房部署了 CDH 集群,到 2021 年已存儲和處理 PB 級的數據。公司自創立以來一直保持每年翻一番的高增長,而比業務量增長更快的是 Hadoop 集群的數據量。
在這幾年間,按 1 到 2 年規劃的硬體,往往因數據增長超出預期而在半年後不得不再次擴容。每次擴容周期可達到一個月,除了花費大量精力跟進行政和技術流程,業務端也不得不安排較多人日控制數據量。
為了降低運維難度,發展可持續擴張的大數據處理方案,我們從 2021 年 10 月份開始探索取代現有Hadoop 集群的方案。當時提出了這些需求:
- 上雲,彈性伸縮、靈活運維
- 存儲計算分離
- 盡量使用開源組件,避免雲廠商綁定
- 盡量降低業務遷移工作量
最終選擇的方案是使用阿里雲 EMR + JuiceFS + 阿里雲 OSS 來搭建存算分離的大數據平台,將雲下數據中心的業務逐步遷移上雲。截至目前(2022 年 7 月)整體遷移進度約 40%,計劃在 2022 年內完成全部業務的搬遷,屆時雲上 EMR 的數據量預計會超過單副本 1 PB.
技術選型
首先是決定使用哪家雲廠商。由於業務需求,AWS、Azure 和阿里雲都有在用,綜合考慮後認為阿里雲最適合,有這些因素:
- 物理距離:阿里雲在我們線下機房同城有可用區,網路專線的延遲小,成本低
- 開源組件齊全:阿里雲 EMR 上包含的開源組件很多很全,除了我們重度使用的 Hive、Impala、Spark、Hue,也能方便集成 Presto、Hudi、Iceberg 等。我們在調研時發現只有阿里雲 EMR 自帶了 Impala,AWS 和 Azure 要麼版本低,要麼要自己安裝部署。
阿里雲的 EMR 本身也有使用 JindoFS 的存算分離方案,但基於以下考慮,我們最終選擇了JuiceFS:
- JuiceFS 使用 Redis 和對象存儲為底層存儲,客戶端完全是無狀態的,可以在不同環境訪問同一個文件系統,提高了方案的靈活性。而 JindoFS 元數據存儲在 EMR 集群的本地硬碟,不便於維護、升級和遷移。
- JuiceFS 的存儲方案豐富,而且支援不同方案的在線遷移,提高了方案的可移植性。JindoFS 塊數據只支援 OSS.
- JuiceFS 以開源社區為基礎,支援所有公有雲環境,方便後期擴展到多雲架構。
關於 JuiceFS
直接截取官方文檔的介紹:
JuiceFS 是一款面向雲原生設計的高性能共享文件系統,在 Apache 2.0 開源協議下發布。提供完備的 POSIX 兼容性,可將幾乎所有對象存儲接入本地作為海量本地磁碟使用,亦可同時在跨平台、跨地區的不同主機上掛載讀寫。
JuiceFS 採用「數據」與「元數據」分離存儲的架構,從而實現文件系統的分散式設計。使用 JuiceFS 存儲數據,數據本身會被持久化在對象存儲(例如,Amazon S3),相對應的元數據可以按需持久化在 Redis、MySQL、TiKV、SQLite 等多種資料庫中。
除了 POSIX 之外,JuiceFS 完整兼容 HDFS SDK,與對象存儲結合使用可以完美替換 HDFS,實現存儲和計算分離。
實施過程
我們在 2021 年 10 月開始探索 Hadoop 的上雲方案;11 月做了大量調研和討論,基本確定方案內容;12 月和 2022 年 1 月春節前做了 PoC 測試,在春節後 3 月份開始搭建正式環境並安排遷移。為了避免導致業務中斷,整個遷移過程以相對較慢的節奏分階段執行,截至目前(2022 年 7 月)進度約 40%,計劃在 2022 年內完成整體的搬遷。 遷移完後,雲上的 EMR 集群數據量預計會超過單副本 1 PB.
架構設計
做完技術選型之後,架構設計也能很快確定下來。考慮到除了 Hadoop 上雲之外,仍然有大部分業務會繼續保留在數據中心,所以整體實際上是個混合雲的架構。
部署和配置
- 關於IDC-阿里雲專線:能提供專線服務的供應商很多,包括 IDC、阿里雲、運營商等,選擇的時候主要考慮線路品質、成本、施工周期等因素,最終我們選擇了IDC的方案。IDC 跟阿里雲有合作,很快就完成了專線的開通。這方面如果遇到問題,可以找 IDC 和阿里雲的支援。除專線租用成本,阿里雲也會收取下行(從阿里雲到 IDC)方向傳輸費用。專線兩端的內網 IP 完全互通,阿里雲和 IDC 兩側都需要一些路由配置。
- 關於EMR Core/Task 節點類型的選擇:
- JuiceFS 可以使用本地硬碟做快取,能進一步減少 OSS 頻寬需求並提高 EMR 性能。更大的本地存儲空間,可以提供更高的快取命中率。
- 阿里雲本地 SSD 實例是較高性價比的 SSD 存儲方案(相對於雲盤),用作快取正合適。
- JuiceFS 社區版未支援分散式快取,意味著每一個節點都需要一個快取池,所以應該選用盡量大的節點。
基於以上考慮和配置對比,我們決定選用 ecs.i2.16xlarge,每個節點64 vCore、512GiB Memory、1.8T*8 SSD。
-
關於 EMR 版本:
軟體方面,主要包括確定組件版本、開啟集群、修改配置。我們機房使用的是 CDH 5.14,其中 Hadoop 版本是 2.6,阿里雲上最接近的版本是 EMR 3.38. 但調研時發現該版本的 Impala 和 Ranger 不兼容(實際上我們機房使用的是 Sentry 做許可權管理,但 EMR 上沒有),最終經過評估對比,決定直接使用 EMR 5 的最新版,幾乎所有組件的大版本都做了升級(包含 Hadoop 3、Spark 3 和 Impala 3.4)。此外,使用外部 MySQL 作為 Hive Metastore、Hue、Ranger 的資料庫。 -
關於 JuiceFS 配置:
基本參考JuiceFS官方文檔《在 Hadoop 中通過 Java 客戶端訪問 JuiceFS》即可完成配置。另外我們也配置了這些參數: -
快取相關:其中最重要的是
juicefs.cache-dir
快取目錄。這個參數支援通配符,對多個硬碟的實例環境很友好,如設置為/mnt/disk*/juicefs-cache
(需要手動創建目錄,或在EMR節點初始腳本中創建),即用全部本地 SSD 作為快取。另外也要關注juicefs.cache-size
、juicefs.free-space
兩個參數。 -
juicefs.push-gateway
:設置一個 Prometheus Push Gateway,用於採集 JuiceFS Java 客戶端的指標。 -
juicefs.users
、juicefs.groups
:分別設置為 JuiceFS 中的一個文件(如jfs://emr/etc/users
、jfs://emr/etc/groups
),解決多個節點 uid 和 gid 可能不統一的問題。 -
關於 Kafka Connect 使用 JuiceFS:
經過一些測試,確認 JuiceFS 可以完美應用於 Kafka Connect 的 HDFS Sink 插件(我們把配置方式也補充到了官方文檔)。相比使用 HDFS Sink 寫入HDFS,寫入 JuiceFS 需要增加或修改以下配置項:
- 將 JuiceFS Java SDK 的 JAR 包發布到 Kafka Connect 每一個節點的 HDFS Sink 插件目錄。Confluent 平台的插件路徑是:
/usr/share/java/confluentinc-kafka-connect-hdfs/lib
- 編寫包含 JuiceFS 配置的
core-site.xml
,發布到 Kafka Connect 每一個節點的任意目錄。包括這些必須配置的項目:
fs.jfs.impl = io.juicefs.JuiceFileSystem
fs.AbstractFileSystem.jfs.impl = io.juicefs.JuiceFS
juicefs.meta = redis://:[email protected]:6379/1
請參見 JuiceFS Java SDK 的配置文檔。
- Kafka Connector 任務設置:
hadoop.conf.dir=<core-site.xml所在目錄>
store.url=jfs://<JuiceFS文件系統名稱>/<路徑>
PoC
PoC 的目的是快速驗證方案的可行性,有幾個具體目標:
- 驗證 EMR + JuiceFS + OSS 整體方案的可行性
- 檢查 Hive、Impala、Spark、Ranger 等組件版本的兼容性
- 評估對比性能表現,用了 TPC-DS 的測試用例和部分內部真實業務場景,沒有非常精確的對比,但能滿足業務需求
- 評估生產環境所需的節點實例類型和數量(算成本)
- 探索數據同步方案
- 探索驗證集群與自研 ETL 平台、Kafka Connect 等的集成方案
期間做了大量測試、文檔調研、內外部(阿里雲 + JuiceFS 團隊)討論、源碼理解、工具適配等工作,最終決定繼續推進。
數據同步
要遷移的數據包括兩部分:Hive Metastore 元數據以及 HDFS 上的文件。由於不能中斷業務,採用存量同步 + 增量同步(雙寫)的方式進行遷移;數據同步完後需要進行一致性校驗。
存量同步
對於存量文件同步,可以使用 JuiceFS 提供的功能完整的數據同步工具 sync 子命令 來實現高效遷移。JuiceFS sync 命令支援單節點和多機並發同步,實際使用時發現單節點開多執行緒即可打滿專線頻寬,CPU 和記憶體佔用低,性能表現非常不錯。
Hive Metastore 的數據同步則相對麻煩些:
- 兩個 Hive 版本不一致,Metastore 的表結構有差異,因此無法直接使用 MySQL 的導出導入功能
- 遷移後需要修改庫、表、分區存儲路徑(即
dbs
表的DB_LOCATION_URI
和sds
表的LOCATION
)
因此我們開發了一套腳本工具,支援表和分區粒度的數據同步,使用起來很方便。
增量同步
增量數據主要來自兩個場景:Kafka Connect HDFS Sink 和 ETL 程式,我們採用了雙寫機制。
Kafka Connect 的 Sink 任務都複製一份即可,配置方式上文有介紹。ETL 任務統一在內部自研的低程式碼平台上開發,底層使用 Airflow 進行調度。通常只需要把相關的 DAG 複製一份,修改集群地址即可。實際遷移過程中,這一步遇到的問題最多,花了大量時間來解決。主要原因是 Spark、Impala、Hive 組件版本的差異導致任務出錯或數據不一致,需要修改業務程式碼。這些問題在 PoC 和早期的遷移中沒有覆蓋到,算是個教訓。
數據校驗
數據同步完後需要進行一致性校驗,分三層:
- 文件一致。在存量同步階段做校驗,通常的方式是用 checksum. 最初的 JuiceFS sync 命令不支援 checksum 機制,我們建議和討論後,JuiceFS 團隊很快就加上了該功能(issue,pull request)。除了 checksum,也可考慮使用文件屬性對比的方式:確保兩個文件系統里所有文件的數量、修改時間、屬性一致。比 checksum 的可靠性稍弱,但更輕量快捷。
- 元數據一致。有兩種思路:對比 Metastore 資料庫的數據,或對比 Hive 的 DDL 命令的結果。
- 計算結果一致。即使用 Hive/Impala/Spark 跑一些查詢,對比兩邊的結果是否一致。一些可以參考的查詢:表/分區的行數、基於某個欄位的排序結果、數值欄位的最大/最小/平均值、業務中經常使用的統計聚合等。
數據校驗的功能也封裝到了腳本里,方便快速發現數據問題。
後續計劃
大致有幾個方向:
- 繼續完成剩餘業務的上雲遷移
- 探索 JuiceFS + OSS 的冷熱分級存儲策略。JuiceFS 的文件在 OSS 上完全被打散,無法基於文件級別做分級。目前的思路是將冷數據從 JuiceFS 遷移到 OSS 上,設置為歸檔存儲,修改 Hive 表或分區的 LOCATION,不影響使用。
- 目前 JuiceFS 使用 Redis 作為元數據引擎,假如將來數據量增加,使用 Redis 有壓力的話可能考慮切換為 TiKV 或其他引擎。
- 探索 EMR 的彈性計算實例,爭取能在滿足業務 SLA 的前提下降低使用成本
一手實戰經驗
在整個實施過程中陸陸續續踩了一些坑,積累了一些經驗,分享給大家做參考。
阿里雲 EMR 和組件相關
兼容性
- EMR 5 的 Hive 和 Spark 版本不兼容,無法使用 Hive on Spark,可以把默認的引擎改成 Hive on Tez.
- Impala 的 stats 數據從舊版同步到新版後,可能因為 IMPALA-10230 導致表無法查詢。解決方案是在同步元數據時,將
num_nulls=-1
的改成num_nulls=0
. 可能需要用到 CatalogObjects.thrift 文件。 - 原集群有少量 Textfile 格式的文件用了 snappy 壓縮,新版 Impala 無法讀取,報錯
Snappy: RawUncompress failed
,可能是 IMPALA-10005 導致的。規避方案是不要對 Textfile 文件使用 snappy 壓縮。 - Impala 3.4 相比 2.11 的
CONCAT_WS
函數行為有差異,老版本CONCAT_WS('_', 'abc', NULL)
會返回NULL
,而新版本返回'abc'
. - Impala 3.4 對 SQL 中的保留關鍵字引用更嚴格,必須加上“. 其實一個好習慣是業務程式碼不要使用保留關鍵字。
- PoC 或前期測試的覆蓋度儘可能完整,用真實的業務程式碼去跑。我們在 PoC 和早期遷移的業務中用到的組件特性比較少,基本都是最常用、保持兼容的功能,因此比較順利。但在第二批遷移過程中就暴露出了很多問題,雖然最終都有解決,但花了很多額外的時間去做診斷和定位,打亂了節奏。
性能
- EMR 5 的 Impala 3.4 打了 IMPALA-10695 這個修補程式,支援對
oss://
和jfs://
(本意是支援 JindoFS,但 JuiceFS 也默認使用 jfs 這個 scheme)設置獨立的 IO 執行緒數。在 EMR 控制台上增加或修改 Impala 的配置項num_oss_io_threads
. - 阿里雲 OSS 有帳號級別的頻寬限制,默認 10Gbps,隨著業務規模上升容易成為瓶頸。可以與阿里雲溝通調整。
運維
- EMR 可以關聯一個 Gateway 集群,通常用來部署業務程式。如果要在 Gateway 上用 client 模式提交 Spark 任務,需要先將 Gateway 機器的 IP 加到 EMR 節點的 hosts 文件。默認可以使用 cluster 模式。
- EMR 5 會開啟一個 Spark ThriftServer,在 Hue 上可以直接寫 Spark SQL,用起來很方便。但默認配置有個坑,會寫大量日誌(路徑大概是
/mnt/disk1/log/spark/spark-hadoop-org.apache.spark.sql.hive.thriftserver.HiveThriftServer2-1-emr-header-1.cluster-xxxxxx.out
),導致硬碟寫滿。解決方案有兩個:配置 log rotate 或把spark.driver.extraJavaOptions
配置清空(阿里雲技術支援的建議)。
JuiceFS 相關
- JuiceFS 需要每個節點上具有相同的 UID 和 GID,否則很容易出現許可權問題。有兩種實現方式:修改作業系統的用戶(比較適合新機器,沒有歷史包袱),或者在 JuiceFS 上維護一個用戶映射表。我們之前也分享過一篇 JuiceFS + HDFS 許可權問題定位,有詳細討論。通常需要維護映射的用戶有
impala
,hive
,hadoop
等。如果使用 Confluent Platform 搭建 Kafka Connect,也需要配置cp-kafka-connect
用戶。 - 使用默認的 JuiceFS IO 配置時,相同的寫查詢,Hive on Tez 和 Spark 都比 Impala 快很多(但在機房裡 Impala 更快)。最終發現將
juicefs.memory-size
從默認的300
(MiB) 改成1024
之後 Impala 的寫入性能有成倍的提升。 - 在做 JuiceFS 的問題診斷和分析時,客戶端日誌很有用,需要注意 POSIX 和 Java SDK 的日誌是不一樣的,詳見 JuiceFS 故障診斷和分析 | JuiceFS Document Center
- 注意監控 Redis 的空間用量,Redis 如果滿了,整個 JuiceFS 集群無法寫入。
- 使用 JuiceFS sync 把機房數據往雲上同步時,選擇在有 SSD 的機器上跑,獲得更好的性能。
如有幫助的話歡迎關注我們項目 Juicedata/JuiceFS 喲! (0ᴗ0✿)