一面資料創立於 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 本身也有使用 JindoFS 的存算分離方案,但基於以下考慮,我們最終選擇了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 上雲之外,仍然有大部分業務會繼續保留在資料中心,所以整體實際上是個混合雲的架構。
基於以上考慮和設定對比,我們決定選用 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 需要增加或修改以下設定項:
/usr/share/java/confluentinc-kafka-connect-hdfs/lib
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 的設定檔案。
hadoop.conf.dir=<core-site.xml所在目錄>
store.url=jfs://<JuiceFS檔案系統名稱>/<路徑>
PoC 的目的是快速驗證方案的可行性,有幾個具體目標:
期間做了大量測試、檔案調研、內外部(阿里雲 + JuiceFS 團隊)討論、原始碼理解、工具適配等工作,最終決定繼續推進。
要遷移的資料包括兩部分:Hive Metastore 後設資料以及 HDFS 上的檔案。由於不能中斷業務,採用存量同步 + 增量同步(雙寫)的方式進行遷移;資料同步完後需要進行一致性校驗。
對於存量檔案同步,可以使用 JuiceFS 提供的功能完整的資料同步工具 sync 子命令 來實現高效遷移。JuiceFS sync 命令支援單節點和多機並行同步,實際使用時發現單節點開多執行緒即可打滿專線頻寬,CPU 和記憶體佔用低,效能表現非常不錯。
Hive Metastore 的資料同步則相對麻煩些:
dbs
表的 DB_LOCATION_URI
和 sds
表的 LOCATION
)因此我們開發了一套指令碼工具,支援表和分割區粒度的資料同步,使用起來很方便。
增量資料主要來自兩個場景:Kafka Connect HDFS Sink 和 ETL 程式,我們採用了雙寫機制。
Kafka Connect 的 Sink 任務都複製一份即可,設定方式上文有介紹。ETL 任務統一在內部自研的低程式碼平臺上開發,底層使用 Airflow 進行排程。通常只需要把相關的 DAG 複製一份,修改叢集地址即可。實際遷移過程中,這一步遇到的問題最多,花了大量時間來解決。主要原因是 Spark、Impala、Hive 元件版本的差異導致任務出錯或資料不一致,需要修改業務程式碼。這些問題在 PoC 和早期的遷移中沒有覆蓋到,算是個教訓。
資料同步完後需要進行一致性校驗,分三層:
資料校驗的功能也封裝到了指令碼裡,方便快速發現資料問題。
大致有幾個方向:
在整個實施過程中陸陸續續踩了一些坑,積累了一些經驗,分享給大家做參考。
num_nulls=-1
的改成 num_nulls=0
. 可能需要用到 CatalogObjects.thrift 檔案。Snappy: RawUncompress failed
,可能是 IMPALA-10005 導致的。規避方案是不要對 Textfile 檔案使用 snappy 壓縮。CONCAT_WS
函數行為有差異,老版本 CONCAT_WS('_', 'abc', NULL)
會返回 NULL
,而新版本返回 'abc'
.oss://
和 jfs://
(本意是支援 JindoFS,但 JuiceFS 也預設使用 jfs 這個 scheme)設定獨立的 IO 執行緒數。在 EMR 控制檯上增加或修改 Impala 的設定項 num_oss_io_threads
./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
設定清空(阿里雲技術支援的建議)。impala
, hive
, hadoop
等。如果使用 Confluent Platform 搭建 Kafka Connect,也需要設定 cp-kafka-connect
使用者。juicefs.memory-size
從預設的 300
(MiB) 改成 1024
之後 Impala 的寫入效能有成倍的提升。如有幫助的話歡迎關注我們專案 Juicedata/JuiceFS 喲! (0ᴗ0✿)