Uber使用Apache Hudi構建了一個大規模事務型數據湖

本文最初發佈於Uber工程博客,由InfoQ中文站翻譯並分享。

Apache Hudi是一個存儲抽象框架,幫助分佈式組織構建和管理PB級的數據湖。Apache Hudi非常靈活,還可以操作Hadoop分佈式文件系統(HDFS)或雲存儲。Hudi可以在數據湖上提供原子性、一致性、隔離和持久性(ACID)語義。

從準確預測到達時間到預測最優交通路線,在Uber平臺上提供安全、完美的出行體驗需要可靠的、高性能的大規模數據存儲和分析。2016年,Uber開發了增量處理框架Apache Hudi,爲業務關鍵數據管道提供低延遲、高效率的支持。一年後,我們選擇開源這個解決方案,讓其他依賴數據的組織也可以從中獲益,然後,在2019年,我們更進一步,將其捐贈給了Apache軟件基金會。現在,大約一年半之後,Apache Hudi已經成爲Apache軟件基金會的頂級項目。爲了紀念這一里程碑事件,我們想分享Apache Hudi構建、發佈、優化和畢業的整個過程,希望可以爲更廣大的大數據社區帶來幫助。

Apache Hudi是什麼?

Apache Hudi是一個存儲抽象框架,幫助分佈式組織構建和管理PB級的數據湖。通過使用諸如upsert和incremental pull這樣的原語,Hudi將流式處理引入到批處理風格的大數據中。這些特性有助於爲我們的服務提供更快、更新的數據,它提供了統一的服務層、分鐘級的數據延遲,還避免了維護多個系統的額外開銷。Apache Hudi非常靈活,還可以操作Hadoop分佈式文件系統(HDFS)或雲存儲。

Hudi可以在數據湖上提供原子性、一致性、隔離和持久性(ACID)語義。Hudi的兩個應用最廣泛的特性是upsert和incremental pull,它們讓用戶能夠接收變化數據捕獲的信息,並將它們大規模地應用到數據湖中。爲了實現這一點,Hudi提供了各種可插拔的索引功能,而且有自己的數據索引實現。Hudi能夠控制和管理數據湖中的文件佈局,這非常重要,既擺脫了HDFS命名節點和其他雲存儲的限制,還能通過提高可靠性和查詢性能來保證數據生態系統的健康。爲此,Hudi支持多種查詢引擎集成,如Presto、Apache Hive、Apache Spark和Apache Impala。

圖1 Apache Hudi接收變化日誌、事件和增量流,暴露表的不同視圖來服務於不同的用例。

從高層次上講,Hudi在概念上分爲3個主要組件:需要存儲的原始數據、用於提供upsert功能的數據索引以及用於管理數據集的元數據。在其內部,Hudi維護着在不同時間點上執行的所有操作的時間表,在Hudi中稱爲instants。這讓它可以提供表的即時視圖,同時還支持高效地按到達順序檢索數據。根據時間表上的時刻(換句話說,在數據庫中進行更改的時間),Hudi可以保證操作是原子的、一致的。有了這些信息,Hudi就可以提供同一個Hudi表的不同視圖,包括具有高效列查詢性能的讀優化視圖、用於快速數據攝入的實時視圖和將Hudi表作爲更改日誌流讀取的增量視圖,如圖1所示。

Hudi將數據表組織到分佈式文件系統中的一個基路徑下。表分爲多個分區,每個分區內,文件被組織成文件組,每個組有惟一的文件ID標識。每個文件組包含幾個文件片,每個文件片包含一個基文件(* .parquet),這個文件是在commit/compaction時生成的,同時生成的還有日誌文件(* . log . *),其中包含自基文件創建以來的插入/更新操作。Hudi採用多版本併發控制(MVCC),其中壓縮操作會合並日志和基文件,生成新的文件片,清理操作會處理掉未使用的/舊的文件片,從而回收文件系統上的空間。

Hudi支持兩種表類型:寫時複製和讀時合併。寫時複製表使用列文件格式(例如,Apache Parquet)存儲數據。寫時複製會更新文件的版本,並通過寫時同步合併來重寫文件。

讀取合併表綜合使用了基於列(例如Apache parquet)和行(例如Apache Avro)的文件格式來存儲數據。更新被記錄到增量文件中,然後再壓縮,同步或異步地生成新版本的列文件。

Hudi還支持兩種查詢類型:快照查詢和增量查詢。快照查詢需要在特定提交或壓縮操作時生成表的“快照”。在利用快照查詢時,寫時複製表只暴露最新文件片中的基/列文件,並保證與非Hudi列表相同的列查詢性能。寫時複製提供了替換現有Parquet表的功能,同時提供了更新/刪除及其他功能。對於讀時合併表,快照查詢通過動態合併最新文件片的基文件和增量文件來暴露近實時數據(以分鐘爲單位)。對於寫時複製表,增量查詢提供在特定提交或壓縮之後寫入到表中的新數據,從而可以提供更改流以支持增量數據管道。

Apache Hudi在Uber的使用

在Uber,我們在各種用例中使用了Hudi,從在Uber平臺上提供快速、準確的出行數據,到檢測欺詐行爲,再到在UberEats平臺上推薦餐廳和美食。爲了演示Hudi的工作機制,讓我們來看看,我們如何確保Uber市場上的出行數據在數據湖上是最新的,從而提升Uber平臺上乘客和司機的用戶體驗。旅程的典型生命週期是從乘客請求開始,隨着旅程的進行而繼續,並在旅程結束且乘客到達最終目的地時結束。Uber的核心出行數據以表的形式存儲在Schemaless(Uber的可伸縮數據存儲)中。 在旅程的生命週期中,旅程表中的單個旅程條目可能會經歷多次更新。在Uber實現Hudi之前,一些大型的Apache Spark作業會定期將整個數據集重寫到Apache HDFS,合併上游在線表的插入、更新和刪除,反映旅程狀態的變化。在2016年初(在我們建立Hudi之前),我們一些最大的任務使用了超過1000個執行器,處理超過20TB的數據。這個過程不僅效率不高,而且也難以擴展。公司裏的各個團隊都依賴快速、準確的數據分析來提供高質量的用戶體驗,很明顯,我們目前的解決方案無法滿足需求,它無法通過擴展實現面向數據湖的便捷的增量處理。在使用快照和重載解決方案將數據移動到HDFS時,這種低效率會影響到所有管道,包括使用原始數據的下游ETL。我們看到,隨着規模的擴大,這些問題只會越來越嚴重。

在沒有其他可行的開源解決方案可供我們使用的情況下,我們在2016年底構建並推出了Hudi,用於構建一個事務型數據湖,實現快速、可靠的大規模數據更新。在Uber,第一代Hudi僅使用了寫時複製表,就將作業處理速度提高到每30分鐘20GB,將I/O和寫放大率減少了100倍。到2017年底,Uber的所有原始數據表都採用了Hudi格式,我們的數據湖是全球最大的事務型數據湖之一。

圖2 Hudi的“寫時複製”功能使我們能夠執行文件級的更新,大幅提高了數據新鮮度。

改進Apache Hudi,不只爲Uber

隨着Uber數據處理和存儲需求的增長,Hudi的寫時複製功能開始顯出侷限性,主要是因爲我們需要繼續提高數據的呈現速度和新鮮度。即使使用了Hudi的寫時複製功能,我們的一些表收到的更新也覆蓋了90%的文件,導致數據湖中每個大型表的數據重寫量都在100TB左右。因爲即使只修改一條記錄,寫時複製功能也會重寫整個文件,使寫放大率增加而數據新鮮度降低,導致HDFS集羣上不必要的I/O,加速磁盤性能退化。此外,更多的數據表更新意味着更多的文件版本以及HDFS文件數量的爆炸。反過來,這會導致HDFS命名節點不穩定,計算成本增加。

爲了解決這些日益增多的問題,我們實現了第二種表類型,即讀取合併。由於讀取合併通過動態合併數據來使用近實時數據,所以謹慎起見,我們使用該特性來避免查詢端計算成本。我們的讀取合併部署模型包括三個獨立的作業:一個攝入作業,帶來由插入、更新和刪除組成的新的數據;一個次要壓縮作業,在少量最新的分區中積極地對更新/刪除進行異步壓縮;一個主要壓縮作業,在大量的舊分區中緩慢而穩定地壓縮更新/刪除。每個作業都以不同的頻率運行,次要作業和攝入作業比主要作業運行得更頻繁,從而確保最新分區中的數據能以列格式快速提供。有了這樣一個部署模型,我們就能夠以列格式向數千個查詢提供新數據,並將查詢端合併成本限定在最新的分區上。使用讀取合併,我們能夠解決上面提到的所有三個問題,並且,不管數據湖更新或刪除的量多大,Hudi表都幾乎不受影響。現在,在Uber,我們根據情況同時使用了Apache Hudi的寫時複製和讀時合併功能。

圖3 Uber的Apache Hudi團隊爲讀取合併表開發了一種數據壓縮策略,以便頻繁地將最新分區轉換爲列格式,從而減少查詢端計算成本。

藉助Hudi,Uber每天將超過5000億條的記錄接收到我們150PB的數據湖裏,跨10000多個表和數千條數據管道,每天使用超過30000個虛擬內核。Hudi表每週要爲我們的各種服務提供超過100萬次查詢服務。

回顧

Uber在2017年將Hudi開源,讓其他人可以受益於這樣一個大規模攝入和管理數據存儲的解決方案,將流處理引入大數據。隨着Hudi畢業成爲Apache軟件基金會的頂級項目,Uber的大數據團隊回顧了當初激勵我們創建Hudi的各種考慮,包括:

  • 我們的數據存儲和處理如何才能更高效?
    • 我們如何確保我們的數據湖包含高質量的表?
    • 隨着運營規模的增長,我們如何繼續以較低的延遲高效地提供數據?
    • 如何爲可以延遲幾分鐘的用例提供統一的服務層?

如果沒有良好的標準化和原語,數據湖很快就會變成無法使用的“數據沼澤”。這樣的話,不僅覈對、清理和修復表需要大量的時間和資源,而且各個服務的所有者還不得不爲調優、重排和事務構建複雜的算法,給技術堆棧帶來不必要的複雜性。

如上所述,Hudi通過在分佈式文件系統上無縫地攝入和管理大型分析型數據集來幫助用戶控制他們的數據湖,從而解決了這些問題。構建數據湖涉及多方面的問題,需要投入時間和精力來研究數據標準化、存儲技術、文件管理實踐、在數據攝入和數據查詢之間做恰當的性能取捨等。在構建Hudi的過程中,我們與大數據社區的其他成員進行了交流,我們瞭解到,這樣的問題在許多工程組織中都很普遍。我們希望,在過去的幾年裏,開源以及與Apache社區合作進行的以Hudi爲基礎的構建,能夠讓其他人更深入地瞭解他們自己的大數據運營,從而改進各行業的應用程序。除了Uber,還有多家公司在生產環境中使用了Apache Hudi,其中包括阿里雲、Udemy和騰訊。

展望

圖4 Apache Hudi的用例包括數據分析和基礎設施健康監控。

Hudi幫助用戶構建更健壯、新鮮度更高的數據湖,通過數據集規範化提供高質量的洞察。

Uber擁有世界上最大的事務型數據湖之一,這讓我們有機會找到獨特的Apache Hudi用例。鑑於在這種規模下解決問題和提升效率會產生重大的影響,我們就有了更深入研究的直接動機。在Uber,我們已經使用高級的Hudi原語(如incremental pull)來幫助我們構建鏈式增量管道,減少作業佔用的計算資源,不然的話,這些作業將執行大規模掃描和寫入操作。我們根據自己特定的用例和需求,對讀取合併表的壓縮策略進行了優化。在最近幾個月裏,我們將Hudi捐贈給了Apache基金會,並貢獻了多項功能,比如,支持高效文件系統訪問的嵌入式時間表服務刪除重命名以支持雲友好的部署,以及提高incremental pull性能等等。

在接下來的幾個月裏,Uber打算爲Apache Hudi社區貢獻多項新特性。其中一些特性通過優化計算資源使用以及提高數據應用程序的性能來幫助降低成本。我們還將深入研究如何根據訪問模式和數據應用程序需求改進存儲管理和查詢性能。

要了解關於我們計劃如何實現這些目標的更多信息,可以閱讀一些由Hudi團隊提出、旨在擴展Apache社區的RFC(包括用於支持列索引和O(1)查詢計劃的智能元數據將表高效遷移到Hudi用於快速upsert的記錄級索引)。

Apache Hudi已經畢業成爲頂級Apache項目,我們很高興能爲這個項目的宏偉藍圖做出貢獻。Hudi讓Uber和其他公司能夠提升數據湖的速度、可靠性和事務能力,利用開源文件格式,將許多大數據的挑戰抽象出來,構建豐富的、可移植的數據應用程序。

Apache Hudi是一個正在成長的社區,擁有一個令人興奮的、不斷髮展的開發路線圖。如果你有興趣爲這個項目貢獻,請點擊這裏

關於作者

Nishith Agarwal是Uber和Apache Hudi PMC大數據平臺的工程負責人。他的團隊幫助Uber構建數據湖基礎設施。

查看英文原文:Building a Large-scale Transactional Data Lake at Uber Using Apache Hudi

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