有贊大數據離線集羣遷移實戰

一、背景

有贊是一家商家服務公司,向商家提供強大的基於社交網絡的,全渠道經營的 SaaS 系統和一體化新零售解決方案。隨着近年來社交電商的火爆,有贊大數據集羣一直處於快速增長的狀態。在 2019 年下半年,原有云廠商的機房已經不能滿足未來幾年的持續擴容的需要,同時考慮到提升機器擴容的效率(減少等待機器到位的時間)以及支持彈性伸縮容的能力,我們決定將大數據離線 Hadoop 集羣整體遷移到其他雲廠商。

在遷移前我們的離線集羣規模已經達到 200+ 物理機器,每天 40000+ 調度任務,本次遷移的目標如下:

  • 將 Hadoop 上的數據從原有機房在有限時間內全量遷移到新的機房
  • 如果全量遷移數據期間有新增或者更新的數據,需要識別出來並增量遷移
  • 對遷移前後的數據,要能對比驗證一致性(不能出現數據缺失、髒數據等情況)
  • 遷移期間(可能持續幾個月),保證上層運行任務的成功和結果數據的正確

有贊大數據離線平臺技術架構

上文說了 Hadoop 集羣遷移的背景和目的,我們回過頭來再看下目前有贊大數據離線平臺整體的技術架構,如圖1.1所示,從低往上看依次包括:

圖1.1 有贊大數據離線平臺的技術架構
  • Hadoop 生態相關基礎設施,包括 HDFS、YARN、Spark、Hive、Presto、HBase、Kafka、Kylin等
  • 基礎組件,包括 Airflow (調度)、DataX (離線數據同步)、基於binlog的增量數據同步、SQL解析/執行引擎選擇服務、監控&診斷等
  • 平臺層面,包括: 數據開發平臺(下文簡稱DP)、資產管理平臺、數據可視化平臺、算法訓練平臺等

本次遷移會涉及到從底層基礎設施到上層平臺各個層面的工作。

二、方案調研

在開始遷移之前,我們調研了業界在遷移 Hadoop 集羣時,常用的幾種方案:

2.1 單集羣

兩個機房公用一個 Hadoop 集羣(同一個Active NameNode,DataNode節點進行雙機房部署),具體來講有兩種實現方式:

  • (記爲方案A) 新機房DataNode節點逐步擴容,老機房DataNode節點逐步縮容,縮容之後通過 HDFS 原生工具 Balancer 實現 HDFS Block 副本的動態均衡,最後將Active NameNode切換到新機房部署,完成遷移。這種方式最爲簡單,但是存在跨機房拉取 Shuffle 數據、HDFS 文件讀取等導致的專線帶寬耗盡的風險,如圖2.1所示
  • (記爲方案B) 方案 A 由於兩個機房之間有大量的網絡傳輸,實際跨機房專線帶寬較少情況下一般不會採納,另外一種帶寬更加友好的方案是:
  • 通過Hadoop 的 Rack Awareness 來實現 HDFS Block N副本雙機房按比例分佈(通過調整 HDFS 數據塊副本放置策略,比如常用3副本,兩個機房比例爲1:2)
  • 通過工具(需要自研)來保證 HDFS Block 副本按比例在兩個機房間的分佈(思路是:通過 NameNode 拉取 FSImage,讀取每個 HDFS Block 副本的機房分佈情況,然後在預定限速下,實現副本的均衡)

圖2.1 單集羣遷移方案

優點

  • 對用戶透明,基本無需業務方投入
  • 數據一致性好
  • 相比多集羣,機器成本比較低

缺點

  • 需要比較大的跨機房專線帶寬,保證每天增量數據的同步和 Shuffle 數據拉取的需要
  • 需要改造基礎組件(Hadoop/Spark)來支持本機房優先讀寫、在限速下實現跨機房副本按比例分佈等
  • 最後在完成遷移之前,需要集中進行 Namenode、ResourceManager 等切換,有變更風險

2.2 多集羣

在新機房搭建一套新的 Hadoop 集羣,第一次將全量 HDFS 數據通過 Distcp 拷貝到新集羣,之後保證增量的數據拷貝直至兩邊的數據完全一致,完成切換並把老的集羣下線,如圖2.2所示。

這種場景也有兩種不同的實施方式:

  • (記爲方案C) 兩邊 HDFS 數據完全一致後,一鍵全部切換(比如通過在DP上配置改成指向新集羣),優點是用戶基本無感知,缺點也比較明顯,一鍵遷移的風險極大(怎麼保證兩邊完全一致、怎麼快速識別&快速回滾)
  • (記爲方案D) 按照DP上的任務血緣關係,分層(比如按照數據倉庫分層依次遷移 ODS / DW / DM 層數據)、分不同業務線遷移,優點是風險較低(分治)且可控,缺點是用戶感知較爲明顯

圖2.2 多集羣遷移方案

優點

  • 跨機房專線帶寬要求不高(第一次全量同步期間不跑任務,後續增量數據同步,兩邊雙跑任務不存在跨機房 Shuffle 問題)
  • 風險可控,可以分階段(ODS / DW / DM)依次遷移,每個階段可以驗證數據一致性後再開始下一階段的遷移
  • 不需要改造基礎組件(Hadoop/Spark)

缺點

  • 對用戶不透明,需要業務方配合
  • 在平臺層需要提供工具,來實現低成本遷移、數據一致性校驗等

2.3 方案評估

從用戶感知透明度來考慮,我們肯定會優先考慮單集羣方案,因爲單集羣在遷移過程中,能做到基本對用戶無感知的狀態,但是考慮到如下幾個方面的因素,我們最終還是選擇了多集羣方案:

  • (主因)跨機房的專線帶寬大小不足。上述單集羣的方案 A 在 Shuffle 過程中需要大量的帶寬使用;方案 B 雖然帶寬更加可控些,但副本跨機房複製還是需要不少帶寬,同時前期的基礎設施改造成本較大
  • (次因)平臺上的任務類型衆多,之前也沒系統性梳理過,透明的一鍵遷移可能會產生穩定性問題,同時較難做回滾操作

因此我們通過評估,最終採用了方案 D。

三、實施過程

在方案確定後,我們便開始了有條不紊的遷移工作,整體的流程如圖3.1所示

圖3.1 離線Hadoop多集羣跨機房遷移流程圖

上述遷移流程中,核心要解決幾個問題:

  • 第一次全量Hadoop數據複製到新集羣,如何保證過程的可控(有限時間內完成、限速、數據一致、識別更新數據)?(工具保證)
  • 離線任務的遷移,如何做到較低的遷移成本,且保障遷移期間任務代碼、數據完全一致?(平臺保證)
  • 完全遷移的條件怎麼確定?如何降低整體的風險?(重要考慮點)

3.1 Hadoop 全量數據複製

首先我們在新機房搭建了一套 Hadoop 集羣,在進行了性能壓測和容量評估後,使用 DistCp 工具在老集羣資源相對空閒的時間段做了 HDFS 數據的全量複製,此次複製 HDFS 數據時新集羣只開啓了單副本,整個全量同步持續了兩週。基於 DistCp 本身的特性(帶寬限制:-bandwidth / 基於修改時間和大小的比較和更新:-update)較好的滿足全量數據複製以及後續的增量更新的需求。

3.2 離線任務的遷移

目前有贊所有的大數據離線任務都是通過 DP 平臺來開發和調度的,由於底層採用了兩套 Hadoop 集羣的方案,所以遷移的核心工作變成了怎麼把 DP 平臺上任務遷移到新集羣。

3.2.1 DP 平臺介紹

有讚的 DP 平臺是提供用戶大數據離線開發所需的環境、工具以及數據的一站式平臺(更詳細的介紹請參考另一篇博客),目前支持的任務主要包括:

  • 離線導入任務( MySQL 全量/增量導入到 Hive)
  • 基於binlog的增量導入 (數據流:binlog -> Canal -> NSQ -> Flume -> HDFS -> Hive)
  • 導出任務(Hive -> MySQL、Hive -> ElasticSearch、Hive -> HBase 等)
  • Hive SQL、Spark SQL 任務
  • Spark Jar、MapReduce 任務
  • 其他:比如腳本任務

本次由於採用多集羣跨機房遷移方案(兩個 Hadoop 集羣),因此需要在新舊兩個機房搭建兩套 DP 平臺,同時由於遷移週期比較長(幾個月)且用戶遷移的時間節奏不一樣,因此會出現部分任務先遷完,部分任務還在雙跑,還有一些任務沒開始遷移的情況。

3.2.2 DP 任務狀態一致性保證

在新舊兩套 DP 平臺都允許用戶創建和更新任務的前提下,如何保證兩邊任務狀態一致呢(任務狀態不限於MySQL的數據、Gitlab的調度文件等,因此不能簡單使用MySQL自帶的主從複製功能)?我們採取的方案是通過事件機制來實現任務操作時間的重放,展開來講:

  • 用戶在老 DP 產生的操作(包括新建/更新任務配置、任務測試/發佈/暫停等),通過事件總線產生事件消息發送到 Kafka,新系統通過訂閱 Kafka 消息來實現事件的回放,如圖 3.2 所示。

圖3.2 通過事件機制,來保證兩個平臺之間的任務狀態一致

3.2.3 DP 任務遷移狀態機設計

DP 底層的改造對用戶來說是透明的,最終暴露給用戶的僅是一個遷移界面,每個工作流的遷移動作由用戶來觸發。工作流的遷移分爲兩個階段:雙跑和全部遷移,狀態流轉如圖 3.3 所示

圖3.3 工作流遷移狀態流轉
雙跑

工作流的初始狀態爲未遷移,然後用戶點擊遷移按鈕,會彈出遷移界面,如圖 3.4 所示,用戶可以指定工作流的任意子任務的運行方式,主要選項如下:

  • 兩邊都跑:任務在新老環境都進行調度
  • 老環境跑:任務只在老環境進行調度
  • 新環境跑:任務只在新環境進行調度

圖3.4 工作流點擊遷移時,彈框提示選擇子任務需要運行的方式

不同類型的子任務建議的運行方式如下:

  • 導入任務 (MySQL -> Hive):通常是雙跑,也就是兩個集羣在調度期間都會從業務方的 MySQL 拉取數據(由於拉取的是 Slave 庫,且全量拉取的一般是數據量不太大的表)
  • Hive、SparkSQL 任務:通常也是雙跑,雙跑時新老集羣都會進行計算。
  • MapReduce、Spark Jar 任務:需要業務方自行判斷:任務的輸出是否是冪等的、代碼中是否配置了指向老集羣的地址信息等
  • 導出任務:一般而言無法雙跑,如果兩個環境的任務同時向同一個 MySQL表(或者 同一個ElasticSearch 索引)寫入/更新數據,容易造成數據不一致,建議在驗證了上游 Hive 表數據在兩個集羣一致性後進行切換(只在新環境跑)。
  • 同時處於用戶容易誤操作導致問題的考慮,DP 平臺在用戶設置任務運行方式後,進行必要的規則校驗:
  • 如果任務狀態是雙跑,則任務依賴的上游必須處於雙跑的狀態,否則進行報錯。
  • 如果任務是第一次雙跑,會使用 Distcp 將其產出的 Hive 表同步到新集羣,基於 Distcp 本身的特性,實際上只同步了在第一次同步之後的增量/修改數據。
  • 如果工作流要全部遷移(老環境不跑了),則工作流的下游必須已經全部遷移完。

雙跑期間的數據流向如下圖 3.5 所示:

圖3.5 DP 任務雙跑期間數據流向
遷移過程中工作流操作的限制規則

由於某個工作流遷移的持續時間可能會比較長(比如DW層任務需要等到所有DM層任務全部遷移完),因此我們既要保證在遷移期間工作流可以繼續開發,同時也要做好預防誤操作的限制,具體規則如下:

  • 遷移中的工作流在老環境可以進行修改和發佈的,新環境則禁止
  • 工作流在老環境修改發佈後,會將修改的元數據同步到新環境,同時對新環境中的工作流進行發佈。
  • 工作流全部遷移,需要所有的下游已經完成全部遷移。

3.3 有序推動業務方遷移

工具都已經開發好了,接下來就是推動 DP 上的業務方進行遷移,DP 上任務數量大、種類多、依賴複雜,推動業務方需要一定的策略和順序。有讚的數據倉庫設計是有一定規範的,所以我們可以按照任務依賴的上下游關係進行推動:

  • 導入任務( MySQL 全量/增量導入 Hive) 一般屬於數據倉庫的 ODS 層,可以進行全量雙跑。
  • 數倉中間層任務主要是 Hive / Spark SQL 任務,也可以全量雙跑,在驗證了新老集羣的 Hive 表一致性後,開始推動數倉業務方進行遷移。
  • 數倉業務方的任務一般是 Hive / Spark SQL 任務和導出任務,先將自己的 Hive 任務雙跑,驗證數據一致性沒有問題後,用戶可以選擇對工作流進行全部遷移,此操作將整個工作流在新環境開始調度,老環境暫停調度。
  • 數倉業務方的工作流全部遷移完成後,將導入任務和數倉中間層任務統一在老環境暫停調度。
  • 其他任務主要是 MapReduce、Spark Jar、腳本任務,需要責任人自行評估。

3.4 過程保障

工具已經開發好,遷移計劃也已經確定,是不是可以讓業務進行遷移了呢?慢着,我們還少了一個很重要的環節,如何保證遷移的穩定呢?在遷移期間一旦出現 bug 那必將是一個很嚴重的故障。因此如何保證遷移的穩定性也是需要着重考慮的,經過仔細思考我們發現問題可以分爲三類,遷移工具的穩定,數據一致性和快速回滾。

遷移工具穩定

  • 新 DP 的元數據同步不及時或出現 Bug,導致新老環境元數據不一致,最終跑出來的數據必定天差地別。
  • 應對措施:通過離線任務比對兩套 DP 中的元數據,如果出現不一致,及時報警。
  • 工作流在老 DP 修改發佈後,新 DP 工作流沒發佈成功,導致兩邊調度的 airflow 腳本不一致。
  • 應對措施:通過離線任務來比對 airflow 的腳本,如果出現不一致,及時報警。
  • 全部遷移後老環境 DP 沒有暫定調度,導致導出任務生成髒數據。
  • 應對措施:定時檢測全部遷移的工作流是否暫停調度。
  • 用戶設置的運行狀態和實際 airflow 腳本的運行狀態不一致,比如用戶期望新環境空跑,但由於程序 bug 導致新環境沒有空跑。
  • 應對措施:通過離線任務來比對 airflow 的腳本運行狀態和數據庫設置的狀態。

Hive 表數據一致性

Hive 表數據一致性指的是,雙跑任務產出的 Hive 表數據,如何檢查數據一致性以及識別出來不一致的數據的內容,具體方案如下(如圖3.6所示):

  • 雙跑的任務在每次調度運行完成後,我們會上報 <任務T、產出的表A> 信息,用於數據質量校驗(DQC),等兩個集羣產出的表A都準備好了,就觸發數據一致性對比
  • 根據 <表名、表唯一鍵K> 參數提交一個 MapReduce Job,由於我們的 Hive 表格式都是以 Orc格式存儲,提交的 MapReduce Job 在 MapTask 中會讀取表的任意一個 Orc 文件並得到 Orc Struct 信息,根據用戶指定的表唯一鍵,來作爲 Shuffle Key,這樣新老表的同一條記錄就會在同一個 ReduceTask 中處理,計算得到數據是否相同,如果不同則打印出差異的數據
  • 表數據比對不一致的結果會發送給表的負責人,及時發現和定位問題

圖3.6 Hive表新老集羣數據一致性校驗方案

四、遷移過程中的問題總結

  • 使用 DistCp 同步 HDFS 數據時漏配參數(-p),導致 HDFS 文件 owner 信息不一致。
  • 使用 DistCp 同步 HDFS 數據時覆蓋了 HBase 的 clusterId,導致 Hbase 兩個集羣之間同步數據時發生問題。
  • 在遷移開始後,新集羣的 Hive 表通過 export import 表結構來創建,再使用 DistCp 同步表的數據。導致 Hive meta 信息丟失了 totalSize 屬性,造成了 Spark SQL 由於讀取不到文件大小信息無法做 broadcast join,解決方案是在 DistCp 同步表數據之後,執行 Hive 命令 ANALYZE TABLE TABLE_NAME COMPUTE STATISTICS 來生成表相關屬性。
  • 遷移期間由於在夜間啓動了大量的 MapReduce 任務,進行 Hive 表數據比對,佔用太多離線集羣的計算資源,導致任務出現了延遲,最後將數據比對任務放在資源相對空閒的時間段。
  • 工作流之間存在循環依賴,導致雙跑-全部遷移的流程走不下去,所以數倉建設的規範很重要,解決方案就是要麼讓用戶對任務重新組織,來重構工作流的依賴關係,要麼兩個工作流雙跑後,一起全部遷移。
  • 遷移期間在部分下游已經全部遷移的情況下,上游出現了問題需要重刷所有下游,由於只操作了老 DP,導致新環境沒有重刷,使遷移到新環境的下游任務受到了影響。
  • MapReduce 和 Spark Jar 類型的任務無法通過代碼來檢測生成的上下游依賴關係,導致這類任務只能由用戶自己來判斷,存在一定的風險,後續會要求用戶對這類任務也配上依賴的 Hive 表和產出的 Hive 表。

五、總結與展望

本次的大數據離線集羣跨機房遷移工作,時間跨度近6個月(包括4個月的準備工作和2個月的遷移),涉及PB+的數據量和4萬日均調度任務。雖然整個過程比較複雜(體現在涉及的組件衆多、任務種類和實現複雜、時間跨度長和參與人員衆多),但通過前期的充分調研和探討、中期的良好遷移工具設計、後期的可控推進和問題修復,我們做到了整體比較平穩的推進和落地。同時針對遷移過程中遇到的問題,在後續的類似工作中我們可以做的更好:

  • 做好平臺的治理,比如代碼不能對當前環境配置有耦合
  • 完善遷移工具,儘量讓上層用戶無感知
  • 單 Hadoop 集羣方案的能力儲備,主要解決跨機房帶寬的受控使用

本文轉載自公衆號有贊coder(ID:youzan_coder)。

原文鏈接

https://mp.weixin.qq.com/s?__biz=MzAxOTY5MDMxNA==&mid=2455761155&idx=1&sn=e897a1fe4771df24ea2acb284ecfc28d&chksm=8c687726bb1ffe3096e9243b275b95735210a92f992d1833143e1ccaa0114bfdbb070d3c0615&scene=27#wechat_redirect

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章