快手流批一體資料湖構建實踐

陶然陶然發表於2023-05-17

  本次將介紹快手為什麼建設資料湖,在資料湖建設過程中遇到的問題和取得的成果,並對未來發展進行展望。

   01 資料湖架構:從離線數倉到湖倉一體的轉變

  資料建設的核心目標一般為:

  ① 標準統一;

  ② 可共享;

  ③ 簡單易用;

  ④ 高效能;

  ⑤ 成熟安全可靠。

  但是,現在常用來作為實現方案的 Lambda 架構,架構一般如下:

  這裡存在三個比較嚴重的問題:

  ① 離線鏈路時效性差。若是直接在這個鏈路上進行提效,則需要的成本比較高。

  ② 處理邏輯異構。由於目前將實時資料和離線資料分成了兩個鏈路來處理資料,導致很多的處理邏輯無法複用。同時,也會存在一致性的問題。

  ③ 資料孤島。本身多個鏈路的生產會存在資料孤島,資料無法複用,並且管理相當複雜。

  為了解決上述問題,快手使用了資料湖作為資料建設的一個集中式倉儲方案。同時,資料湖也能夠滿足資料建設的核心目標。資料湖具有以下特性:

  ① 海量儲存;

  ② 支援可擴充套件的資料型別;

  ③ Schema 演進;

  ④ 支援可擴充套件的資料來源;

  ⑤ 強大的資料管理能力;

  ⑥ 高效資料處理;

  ⑦ 高效能的分析。

  業內有很多的資料湖開源實現方案,快手對這些方案的基礎優勢及特性、社群建設情況和技術開發的可擴充套件程度進行了比較,最終選擇了 Hudi 作為資料湖實現方案。Hudi 在攝入、處理、儲存到查詢,基礎能力支援地比較完善,其具有的多個特點能夠支援資料湖的快速構建和應用,這些特點包括:更新能力強,支援流批讀寫,可插拔的 Payload,支援 MOR 表型別,適配多種查詢引擎,豐富的資料管理操作等。

  Hudi 可以幫助快手構建更優的資料鏈路,去完成資料建設的核心目標,架構參考如下:

  快手基於 Hudi 構建的資料湖架構具有以下優勢:

  ① 資料 CURD。最佳化生產場景模型,提升了整體更新場景的時效;

  ② 流批讀寫。實現統一的處理,減少了多鏈路多引擎的建設成本;

  ③ 海量資料管理。對所有的入湖資料進行統一管理,資料平臺的服務和管理方面能夠複用,降低資料的使用成本。

   02 基於 Hudi 快速構建快手資料湖:建設快手資料湖遇到的挑戰以及解決方案

  如何使用 Hudi 建設達到核心目標,需要先了解 Hudi 的基本能力:

  ① 支援不同型別的寫入方式:特別是透過增量寫入和資料合併的兩個基本操作,實現快照的生成;

  ② 可插拔:可支援所需要的更新邏輯,比如定製化更新模式,可以基於此進行擴充套件應用場景;

  ③ 表型別:正如前面提到的,增量寫入和資料合併的操作共同組成快照更新。這兩種基本操作的實現決定了表的型別。不同型別的表,作用不同的應用場景,比如寫多讀少的情況下,選擇使用 MOR 更實時和節約資源;

  ④ 後設資料統計:因為 Hudi 本身實現了更新能力,甚至在之上實現一部分的業務邏輯的,需要保障可描述、可追溯的能力。所以透過後設資料的收集和應用,來保證資料的可追溯性;

  ⑤ 讀取方式:支援 Hadoop 的 inputformat 的方式,相容常用的查詢引擎,比如spark、trino 等。

  使用這些能力,可以為生產鏈路實現提效與統一。

  提效主要還是在最佳化構建離線數倉的時間:

  ① 比如分層建設時,需要先同步資料,然後再使用離線清洗,再生成後續的數倉的加工資料。現在可以直接一步透過 Flink 任務清洗實時資料,然後使用 Hudi 多級動態分割槽同步。

  ② 還有,在離線鏈路生產時,有些資料生產是有更新邏輯的,比如更改部分資料內容。在老的架構下,需要將所有資料都讀取一遍,然後將修改了某幾列的新資料再完全寫入。這裡不但時效很差,而且成本消耗很大。現在可以利用 Hudi 的更新能力來高效地更新列資料。

  ③ 其他的,比如活動的資料需要進行快照分析時,離線鏈路都是小時級別的延遲,一般都需要使用實時鏈路同時生產。使用 Hudi 就可以進行準實時快照的構建,並提供相容的查詢。

  統一的實現,主要是選用了 Flink 引擎作為流批一體的計算引擎,在整體 Hudi 資料湖的生產中進行應用。

  透過 Hudi 資料湖架構建設的資料鏈路如下所示:

  快手在透過 Hudi 資料湖架構建設新的資料鏈路中,遇到了許多問題。下面,介紹一下快手在建設資料湖過程中遇到的 5 個重要問題以及具體的解決方案。

  1. 資料攝入的瓶頸

  問題描述

  快手的資料鏈路都是基於 Flink 生產的,其 Hudi On Flink 架構如下圖所示。

  採用上述架構進行資料生產時會遇到效能瓶頸。由於寫入多分割槽的資料時會透過 BucketAssigner 來進行資料分發,再使用 BucketWriter 實現快取寫入,那麼,當 BucketWriter 之間資料不均衡時,寫入會頻繁觸發溢寫。而當溢寫發生時,又會產生背壓。另外,在提交資料時,由於 BucketWriter 與 Flink 快照進行了繫結,所以 Flink 快照無法實現整點觸發。

  解決方案

  為了解決上述提到的寫入瓶頸問題,快手最佳化了寫入邏輯,主要應用於增量資料的同步鏈路。首先,最佳化寫入模式以提升效能。Flink 寫入方式從快取寫入修改為流式寫入。寫入資料時不需要快取,而是直接落盤,並且支援單生產者多消費者的模式,每一個分割槽檔案都可以並行寫入。這樣,可以提高 CPU 的使用率。其次,在攝入的過程中對分發邏輯進行了最佳化,實現了一個動態感知的模組。該模組用於統計資料流量,均衡分發資料到寫入節點,從而保證了各分割槽之間的資料均衡,來避免某個寫入節點受到過大的資料壓力。

  為了實現資料的整點提交,快手實現了自動分割槽釋出功能。根據資料的時間戳生成了分割槽時間,並且在攝入過程中實時上傳資料的輪轉的時間。在中心協調器裡面實現了一個判斷邏輯,如果所有的節點均已完成輪轉,則進行快照的觸發,完成最終的資料提交和分割槽的同步,來實現整點級的分割槽釋出。

  在上述架構中,運算元可以進行橫向擴充套件,整體吞吐量比社群版本提升 10 倍以上,並且能將檔案控制在需要的大小(例如:256M)左右。

  2. 無法使用資料時間進行快照查詢

  問題描述

  在準實時的資料鏈路上,需要使用 Hudi 的 Time Travel 功能來實現快照查詢。但是,在 SQL 查詢是使用 Timeline 的時間點來進行定位的,而 Timeline 的時間與資料時間不同,且具體的 Timeline 的提交時間在儲存時無法準確感知。

  解決方案

  快手在 Hudi 的 Time Travel 功能上增加了一個時間版本的元資訊。每次寫入時,會透過資料的時間欄位來計算資料的版本號。與分割槽釋出過程相同,會實時上傳版本的輪轉時間。在中心協調器判斷是否所有分割槽已經完成了輪轉,以快照觸發。  

  由於在提交時儲存快照的資料版本資訊,在查詢時,SQL 可以直接使用版本資訊來進行查詢。在構建輸入快照的過程中間,會讀取 TimeTravel 的提交資訊。這樣,透過判斷資料版本資訊是否小於等於 SQL 中指定的時間戳的版本號來構建增量快照,實現某一個時間點的快照查詢。

  3. Flink On Hudi 的更新瓶頸

  問題描述

  在使用 Flink 引擎生產 Hudi 表的過程中,更新是存在一定的瓶頸的。主要體現在,對 Hudi 的不同操作使用的資源是錯配的。比如,寫入操作的寫入記憶體一般就是攝入的快取大小。而對於合併操作,合併過程會根據增量資料的資料量來決定 compaction 所需要的記憶體,一般情況下,這個記憶體佔用量是大於快取空間的。清理操作中,在構建 FileSystemView 物件時,所佔用的記憶體比較大。

  然後,混合操作會影響增量寫入的穩定性。比如合併過程中,併發度無法進行擴充套件,會導致執行時間長,進而導致快照產生時間延遲(因為快照觸發是需要水位(watermark)下推),甚至會導致任務超時。清理的時候如果遇到異常,也會導致任務的失敗。因此,操作之間的資源複用對操作的執行進度會有影響。

  解決方案

  解決問題的主要工作是將操作進行分離,支援多種操作並行執行來構建 Hudi 的資料來源。

  首先,Hudi 支援多種索引。在快手活動期間,會選用 State Index,配置 TTL 來儲存一定時間內的快照結果。在需要併發寫入的任務中,由於任務的索引需要相互感知,因此會選用 Bucket Index,可以有效控制寫入快取資源的佔用,而且可以在外部進行操作的執行管理。在表建立時,觸發生成和合並的排程作業;表下線時,自動下線掛載的排程作業。

  此外,多個資料來源的寫入還需要實現併發控制。首先,對後設資料進行加鎖,來避免對後設資料的併發操作。然後,在支援併發寫入的過程中,支援了關聯引用,為合併的功能增加了佔位邏輯,後續的寫入基於佔位合併的 instant,在合併完成之後,基於合併的寫入也是對外可見的,這種方式可以提高寫入的吞吐量。此外,也支援開啟 OCC 控制的併發寫入,在寫入相同的 base 檔案時進行併發檢查,支援衝突的失敗回滾或者合併處理,以防止資料結果不正確的現象出現。

  4. 多工合併能力不足

  問題描述

  多工合併寬表時,在多工併發執行寫入的場景中,進行索引選擇時,需要考慮到索引資料需要被多工感知到的因素。若是採用外部索引,則使用成本較高。若是採用 Bucket Index 作為索引,則進行多工併發寫入時,效能上有優勢。但是,存在一個合併時的瓶頸,這是由於一般情況下,Bucket Index 使用檔案大小來控制計算桶數,而合併時使用的資源又取決於增量檔案的資料大小,這會導致合併任務的併發度較小,無法滿足合併時的效能需求。在合併的過程中,存在讀取和更新的操作,若是過程中出現了溢寫現象,則整個合併速度會很慢。

  在 Schema 的使用方面。不同的寫入任務會使用不同的 Schema,而合併時依賴於寫入任務的 Schema 來生成合並的 Schema 以生成最終的 Base 檔案。但是,一些自動上線的寫入任務無法被合併作業感知到。

  解決方案

  快手實現的併發寫入作業支援了邏輯分桶和多型別合併的能力。邏輯分桶是在物理桶的組織之上進行了二次雜湊,本質上是將物理桶分成了更多的桶,在需要寫入時,要先進行桶的排序,並建立對應的索引檔案。在後續的合併過程中,基於邏輯桶來生成合並計劃,每一個邏輯桶都會生成一個對應的運算元例項。

  合併時,作業先讀取物理桶的資料,然後透過索引 seek 到對應邏輯桶的資料位置,之後進行可選擇型別的合併。一般地,在寫入併發已知的情況下,sortMerge 是更快的。在後設資料中,增加了合併 Schema 的配置,在寫入時將 Schema 更新到資料來源,從而實現了合併Schema的自動擴充套件和合並任務的自動感知生產。

  5. Hudi 生產保障困難

  問題描述

  Hudi 作為一個較複雜的架構,從生產到運維有比較豐富的支援,比如不同模組有對應的配置類,支援 metrics 系統、支援 Hudi-Cli 查詢元資訊。

  但是,這些功能支援在實際生產環境的使用效果並不好。首先,Hudi 的配置過多,使用起來很麻煩。其次,在監控報警和異常中斷的能力上,作為線上服務略顯不足,需要進行自定義強化。因此,快手針對線上需要,加強了生產的保障能力。

  解決方案

  ① 配置精簡。只需要設定一些基本引數(SQL 方式),比如任務型別、儲存時間、提交間隔,就可以自動推導生成其他的配置引數。

  ② 一致性保障。在一致性保障方面,快手自定義實現了 PreCommit 檢驗模組,比如,會對增量資料的輸入輸出條數進行校驗,同時資料塊的寫入情況在提交之前也會做校驗。

  ③ 穩定保障。在穩定性方面,快手完善了不同運算元的 metrics,包括耗時和資料處理情況,流量吞吐情況等。同時還監控著分割槽分佈,耗時,任務的指標監控來共同保障生產的穩定性。

   03 快手的實踐案例

  快手資料湖在構建完成之後,在一些具體的業務上進行了應用,取得了明顯的收益。

  下面使用四個比較典型的案例,來對比基於資料湖建設的新資料鏈路與舊資料鏈路之間的差異。

  最早的時候,核心數倉的 DWD 層生成是需要多層的離線排程任務來進行。在切換到 Hudi 之後,就可以準實時的生成 DWD 層的動態更新資料。此外,還可以根據需要來選擇性的進行資料重分佈的操作來對接下來的讀取操作進行提效。這個場景上,快手將離線鏈路升級成了準實時的鏈路,在計算資源上持平,時效上有 50% 以上的提升。

  資料在應用過程中,還會有活動資料快照查詢的需求。早期,這些資料若要使用多個資料來源進行生產和查詢,需要用到離線鏈路,這種方式的時效性很差,一般會達到小時級。如果想使用實時鏈路加速,需要比較複雜的處理過程。切換到 Hudi 之後,將離線快照的更新時效從小時級縮短到了分鐘級,整體時效達到十多分鐘左右,而且計算資源比以前節省了 15%。在後續的查詢過程中,可以對離線桶的快照資料進行關聯查詢,最終生成需要的活動的結果資料。

  生產過程中的資料留存場景中,在生產留存資料時,最早的生產流程是需要用多天的日活資料去重複地生產標籤表,然後與日活的資料 JOIN 生產到最終日活表內,這個過程涉及多次的日活表的讀取和全量資料的回收。切換至 Hudi 後,透過將日活留存狀態直接更新至留存表,資料生產模式從多次的合併生產轉換成了單表生產。在使用當日的日活資料去更新留存表,之前的資料是已經存在的,只需要將日活資料去更新留存狀態即可。這個場景下,鏈路的生產方式上的最佳化,整體計算資源由於全量讀寫到增量寫入的轉換,根據需求進行定時合併,時效上也有 50% 的提升。

  在特徵的生產場景內,上游的多個資料生產點合併生產出寬表結果。這個場景下,原來是使用 HBase 來進行合併,在 HBase 中進行行存,在外部用 Hbase 進行生產有一個額外的維護成本,並且需要使用到 HBase 的匯入匯出工具來進行離線操作,生產鏈路較長。切換至 Hudi 後,可以直接複用已有的生產鏈路邏輯,然後直接對攝入到 Hudi 表內的資料基於併發合併能力構建一張寬表。這個過程中,也可以保證資料是有序的。例如,讀取時可以根據資料需求,比如上游增量寫入資料來源的資料已經就緒了,下游就可以直接進行匯入。可以理解為實時感知,可以提升整體的處理時效。

  可以的觀察結果為,目前的離線分批的合併升級成了準實時單表合併,對時效升級明顯。首先,處理鏈路的計算時間縮短,最長時間節省 5 個小時;在鏈路計算過程中所佔用的臨時儲存空間和計算資源得到了節省,同時,也節省了 HBase 叢集所需要的開銷。

   04 快手的發展規劃

  快手資料湖當前還有一些待最佳化的工作。首先,缺少完善的後設資料和資料管理服務。在查詢模式上,由於不支援實時表,也還沒有達到離線和實時查詢的統一。此外,當前快手資料湖生產方式還沒有做到無感知的相容,所以主要在新的場景上使用,總體的使用率佔比不高。

  未來快手資料湖將作為統一儲存的技術元件,支援更多型別的資料以及拓寬資料湖支援的表型別,例如實現類似於實時表的定義。完善資料的管理來提升資料組織的合理性。實現相容已有鏈路的輕量切換方案。將實現流批一體的資料生產,提供高效統一的查詢能力作為資料湖建設的最終願景。

來自 “ DataFunTalk ”, 原文作者:鍾靚;原文連結:https://server.it168.com/a2023/0517/6804/000006804055.shtml,如有侵權,請聯絡管理員刪除。

相關文章