1. 引言
從確保準確預計到達時間到預測最佳交通路線,在Uber平臺上提供安全、無縫的運輸和交付體驗需要可靠、高效能的大規模資料儲存和分析。2016年,Uber開發了增量處理框架Apache Hudi,以低延遲和高效率為關鍵業務資料管道賦能。一年後,我們開源了該解決方案,以使得其他有需要的組織也可以利用Hudi的優勢。接著在2019年,我們履行承諾,進一步將其捐贈給了Apache Software Foundation,差不多一年半之後,Apache Hudi畢業成為Apache Software Foundation頂級專案。為紀念這一里程碑,我們想分享Apache Hudi的構建、釋出、優化和畢業之旅,以使更大的大資料社群受益。
2. 什麼是Apache Hudi
Apache Hudi是一個儲存抽象框架,可幫助組織構建和管理PB級資料湖,通過使用upsert和增量拉取等原語,Hudi將流式處理帶到了類似批處理的大資料中。這些功能通過統一的服務層(幾分鐘左右即可實現資料延遲),幫助我們更快,更新鮮地獲取服務資料,從而避免了維護多個系統的額外開銷。更靈活地,Apache Hudi還可以在Hadoop分散式檔案系統(HDFS)或雲端儲存上執行。
Hudi在資料湖上啟用原子性、一致性、隔離性和永續性(ACID)語義。 Hudi的兩個最廣泛使用的功能是upserts和增量拉取,它使使用者能夠捕獲變更資料並將其應用於資料湖,為了實現這一點,Hudi提供了可插拔索引機制,以及自定義索引實現。Hudi具有控制和管理資料湖中檔案佈局的能力,這不僅能克服HDFS NameNode節點和其他雲端儲存限制,而且對於通過提高可靠性和查詢效能來維護健康的資料生態系統也非常重要。另外Hudi支援多種查詢引擎,例如Presto,Apache Hive,Apache Spark和Apache Impala。
圖1. Apache Hudi通過在表上提供不同的檢視來攝取變更日誌、事件和增量流,以服務於不同的應用場景
從總體上講,Hudi在概念上分為3個主要組成部分:需要儲存的原始資料;用於提供upsert功能的索引資料以及用於管理資料集的後設資料。核心方面,Hudi維護在不同時間點在表上執行的所有動作的時間軸,在Hudi中稱為即時,這提供了表格的即時檢視,同時還有效地支援了按序到達的資料檢索,Hudi保證時間軸上的操作是原子性的,並且基於即時時間,與資料庫中進行更改的時間是一致的。利用這些資訊,Hudi提供了同一Hudi表的不同檢視,包括用於快速列式檔案效能的讀優化檢視,用於快速資料攝取的實時檢視以及用於將Hudi表作為變更日誌流讀取的增量檢視,如上圖1所示。
Hudi將資料表組織到分散式檔案系統上基本路徑(basepath)下的目錄結構中。 表分為多個分割槽,在每個分割槽內,檔案被組織成檔案組,由檔案ID唯一標識。 每個檔案組包含幾個檔案切片,其中每個切片包含在某個特定提交/壓縮(commit/compaction)瞬間生成的基本資料檔案(*.parquet),以及包含對基本資料檔案進行插入/更新的一組日誌檔案(*.log)。Hudi採用了Multiversion Concurrency Control(MVCC),其中壓縮操作將日誌和基本檔案合併以生成新的檔案片,而清理操作則將未使用的/較舊的檔案片去除,以回收檔案系統上的空間。
Hudi支援兩種表型別:寫時複製和讀時合併。 寫時複製表型別僅使用列檔案格式(例如,Apache Parquet)儲存資料。通過寫時複製,可以通過在寫過程中執行同步合併來簡單地更新版本並重寫檔案。
讀時合併表型別使用列式(例如Apache Parquet)和基於行(例如Apache Avro)檔案格式的組合來儲存資料。 更新記錄到增量檔案中,然後以同步或非同步壓縮方式生成列檔案的新版本。
Hudi還支援兩種查詢型別:快照查詢和增量查詢。 快照查詢是從給定的提交或壓縮操作開始對錶進行"快照"的請求。利用快照查詢時,寫時複製表型別僅暴露最新檔案片中的基本/列檔案,並且與非Hudi表相比,可保證相同的列查詢效能。寫入時複製提供了現有Parquet表的替代品,同時提供了upsert/delete和其他功能。對於讀時合併表,快照查詢通過動態合併最新檔案切片的基本檔案和增量檔案來提供近乎實時的資料(分鐘級)。對於寫時複製表,自給定提交或壓縮以來,增量查詢將提供寫入表的新資料,並提供更改流以啟用增量資料管道。
3. Apache Hudi在Uber的使用
在Uber,我們在各種場景中都使用到了Hudi,從在Uber平臺上提供有關行程的快速、準確的資料,從檢測欺詐到在我們的UberEats平臺上提供餐廳和美食推薦。為了演示Hudi的工作原理,讓我們逐步瞭解如何確保Uber Marketplace中的行程資料在資料湖上是最新的,從而改善Uber平臺上的騎手和駕駛員的使用者體驗。行程的典型生命週期始於騎手提出的行程,然後隨著行程的進行而繼續,直到行程結束且騎手到達最終目的地時才結束。 Uber的核心行程資料以表格形式儲存在Uber的可擴充套件資料儲存Schemaless中。行程表中的單個行程條目在行程的生命週期中可能會經歷許多更新。在Uber使用Hudi之前,大型Apache Spark作業會定期將整個資料集重新寫入HDFS,以獲取上游線上表的插入、更新和刪除,從而反映出行程狀態的變化。就背景而言,在2016年初(在構建Hudi之前),一些最大的任務是使用1000個executors並處理超過20TB的資料,此過程不僅效率低下,而且難以擴充套件。公司的各個團隊都依靠快速、準確的資料分析來提供高質量的使用者體驗,為滿足這些要求,我們當前的解決方案無法擴充套件進行資料湖上的增量處理。使用快照和重新載入解決方案將資料移至HDFS時,這些低效率的處理正在寫到到所有資料管道,包括使用此原始資料的下游ETL,我們可以看到這些問題只會隨著規模的擴大而加劇。
在沒有其他可行的開源解決方案可供使用的情況下,我們於2016年末為Uber構建並啟動了Hudi,以構建可促進大規模快速,可靠資料更新的事務性資料湖。Uber的第一代Hudi利用了寫時複製表型別,該表型別每30分鐘將作業處理速度提高到20GB,I/O和寫入放大減少了100倍。到2017年底,Uber的所有原始資料表都採用了Hudi格式,執行著地球上最大的事務資料湖之一。
圖2. Hudi的寫時複製功能使我們能夠執行檔案級更新,從而大大提高資料的新鮮度
4. 改進Apache Hudi
隨著Uber資料處理和儲存需求的增長,我們開始遇到Hudi的寫時複製功能的侷限性,主要是需要繼續提高資料的處理速度和新鮮度,即使使用Hudi"寫時複製"功能,我們的某些表收到的更新也分散在90%的檔案中,從而導致需要重寫資料湖中任何給定的大型表的資料,重寫資料量大約為100TB。由於寫時複製甚至為單個修改的記錄重寫整個檔案,因此寫複製功能導致較高的寫放大和損害的新鮮度,從而導致HDFS群集上不必要的I/O以及更快地消耗磁碟空間,此外,更多的資料表更新意味著更多的檔案版本,以及HDFS檔案數量激增,反過來,這些需求導致HDFS Namenode節點不穩定和較高的計算成本。
為了解決這些日益增長的擔憂,我們實現了第二種表型別,即"讀時合併"。由於讀時合併通過動態合併資料來使用近實時的資料,為避免查詢端的計算成本,我們需要合理使用此模式。"讀時合併"部署模型包括三個獨立的作業,其中包括一個攝取作業,包括由插入、更新和刪除組成的新資料,一個次要的壓縮作業,以非同步方式主動地壓縮少量最新分割槽的更新/刪除內容,以及一個主要的壓縮作業,該作業會緩慢穩定地壓縮大量舊分割槽中的更新/刪除。這些作業中的每一個作業都以不同的頻率執行,次要作業和提取作業的執行頻率比主要作業要高,以確保其最新分割槽中的資料以列格式快速可用。通過這樣的部署模型,我們能夠以列式為數千個查詢提供新鮮資料,並將我們的查詢側合併成本限制在最近的分割槽上。使用讀時合併,我們能夠解決上面提到的所有三個問題,並且Hudi表幾乎不受任何對資料湖的更新或刪除的影響。現在,在Uber,我們會根據不同場景同時使用Apache Hudi的寫時複製和讀時合併功能。
圖3. Uber的Apache Hudi團隊開發了一種資料壓縮策略,用於讀時合併表,以便頻繁將最近的分割槽轉化為列式儲存,從而減少了查詢端的計算成本
有了Hudi,Uber每天向超過150PB資料湖中插入超過5,000億條記錄,每天使用30,000多個core,超過10,000多個表和數千個資料管道,Hudi每週在我們的各種服務中提供超過100萬個查詢。
5. Apache Hudi經驗總結
Uber在2017年開源了Hudi,為其他人帶來了該解決方案的好處,該解決方案可大規模提取和管理資料儲存,從而將流處理引入大資料。當Hudi畢業於Apache軟體基金會下的頂級專案時,Uber的大資料團隊總結了促使我們構建Hudi的各種考慮因素,包括:
- 如何提高資料儲存和處理效率?
- 如何確保資料湖包含高質量的表?
- 隨著業務的增長,如何繼續大規模有效地提供低延遲的資料?
- 在分鐘級別的場景中,我們如何統一服務層?
如果沒有良好的標準化和原語,資料湖將很快成為無法使用的"資料沼澤"。這樣的沼澤不僅需要花費大量時間和資源來協調、清理和修復表,而且還迫使各個服務所有者構建複雜的演算法來進行調整、改組和交易,從而給技術棧帶來不必要的複雜性。
如上所述,Hudi通過無縫地攝取和管理分散式檔案系統上的大型分析資料集來幫助使用者控制其資料湖,從而彌補了這些差距。建立資料湖是一個多方面的問題,需要在資料標準化、儲存技術、檔案管理實踐,資料攝取與資料查詢之間折衷效能等方面進行取捨。在我們建立Hudi時與大資料社群的其他成員交談時,我們瞭解到這些問題在許多工程組織中普遍存在。我們希望在過去的幾年中,開源和與Apache社群的合作,在Hudi基礎上發展可以使其他人在不同行業對大資料運營有更深入的瞭解。 在Uber之外,Apache Hudi已在多家公司用於生產,其中包括阿里雲,騰訊雲,AWS、Udemy等。
6. 未來計劃
圖4. Apache Hudi場景包括資料分析和基礎架構執行狀況監視
Hudi通過對資料集強制schema,幫助使用者構建更強大、更新鮮的資料湖,從而提供高質量的見解。
在Uber,擁有全球最大的事務資料湖之一為我們提供了各種Apache Hudi用例場景的機會,由於以這種規模解決問題並提高效率可能會產生重大影響,因此有直接的動機促使我們更加深入。在Uber,我們已經使用了先進的Hudi原語,如增量拉取來幫助建立鏈式增量流水線,從而減少了作業的計算空間,而這些作業本來會執行大型掃描和寫入。我們根據特定的用例場景和要求調整讀時合併表的壓縮策略。 自從我們將Hudi捐贈給Apache基金會以來,最近幾個月,Uber貢獻了一些功能,例如嵌入式時間軸服務以實現高效的檔案系統訪問,刪除重新命名以支援雲友好的部署並提高增量拉取效能。
在接下來的幾個月中,Uber計劃為Apache Hudi社群貢獻更多新功能。其中一些功能可通過優化計算使用量以及改善資料應用程式的效能來幫助降低成本,我們還將更深入地研究如何根據訪問模式和資料應用程式需求來改善儲存管理和查詢效能。
有關我們如何計劃實現這些目標的更多資訊,您可以閱讀一些RFC,包括支援列索引和O(1)查詢計劃的智慧後設資料,將Parquet表高效引導到Hudi,記錄級別索引支援更快速插入,這些RFC由Uber的Hudi團隊向Apache社群提出。
隨著Apache Hudi畢業成為Apache頂級專案,我們很高興為該專案雄心勃勃的路線圖做出貢獻。Hudi使Uber和其他公司可以使用開放原始檔格式,在未來證明其資料湖的速度,可靠性和交易能力,從而消除了許多大資料挑戰,並構建了豐富而可移植的資料應用程式。
Apache Hudi是一個成長中的社群,具有令人興奮且不斷髮展的發展路線圖。 如果您有興趣為這個專案做貢獻,可點選這裡。