本文由 T3 出行大數據平臺負責人楊華和資深大數據平臺開發工程師王祥虎介紹 Flink、Kylin 和 Hudi 湖倉一體的大數據生態體系以及在 T3 的相關應用場景,內容包括:數據庫
- 湖倉一體的架構
- Flink/Hudi/Kylin 介紹與融合
- T3 出行結合湖倉一體的實踐
既然聊湖倉一體,咱們先了解一下什麼是湖,什麼是倉。數據湖是一個很老的概念,在近些年又被熱炒。業界對於數據湖到如今也沒有一個統一的定義。AWS 是最先在雲上推出數據湖解決方案的雲服務提供商,在這裏咱們便引用 AWS 對數據湖的定義:「數據湖是一個集中式的存儲庫,容許存儲任意結構的數據而且能將它應用於大數據處理,以及進行實時分析和機器學習等相關的應用場景。」 一樣咱們也藉助於 AWS 對數據倉庫作這樣的定義:「數據倉庫是信息的一箇中央存儲庫。」 這裏的信息是可對其進行分析,而且可作出更明智的決策。網絡
這個定義還有詳細的展開。AWS 這張圖經過展現了從湖到倉的數據流向的關係,來演示數據湖與數據倉庫之間的區別和聯繫。首先數據最初是存在於數據湖或是數據庫中,而後通過數據篩選和準備以後,就會流向數據倉庫來進行一些高價值的分析。這個對比表格很直觀的從數據、Schema、性價比、數據質量、用戶和分析這 6 個維度給出數據湖和倉的對比。架構
今年咱們據說阿里巴巴說起的「湖倉一體」的概念。不知道你們有沒有想過湖倉一體在業界是否有成功的先例?我我的認爲是有的。今年 (2020年)9 月份,一家叫 Snowflake 的公司在紐交所上市。Snowflake 是一家作雲數倉的公司,基於雲廠商提供的基礎設施提供 SaaS 平臺,面向中小企業提供數據的託管和分析服務。Snowflake 自稱本身是一家雲數倉公司,而且在 16 年的數據頂會上發表了一篇論文來介紹他們彈性數倉的架構以及一些技術的細節。負載均衡
Snowflake 實際上是基於雲上的對象存儲,一份存儲多份計算,而且計算與存儲分離的這樣一套架構。其實這就是 AWS 以及如今主流雲廠商所主推的這個數據湖的架構。Snowflake上市的首日,他的市值就飆升到了 700 億美圓的規模。因此我我的認爲 Snowflake 能夠算是實行湖倉一體的一個最成功的先例。你們能夠去了解一下剛談到的這篇論文。我摘出了這 5 個點來和你們作簡單的分享:框架
這雖然是 16 年的一篇論文,但裏面的觀念並不算陳舊而且仍然值得咱們去學習。後續咱們會簡單介紹幾個被咱們吸取而且將會去實踐的一些點,並且這些點也是 T3 出行在實現湖倉一體上很關鍵的地方。機器學習
首先,做爲一個被不少傳統的數倉普遍應用的一個架構,Shared-Nothing 仍是有一些架構上的優點:分佈式
這套架構其實也有一些不足的地方:函數
同時也帶來第二個問題,就是彈性不足。具體能夠體如今 2 個方面。工具
基於這些問題,Snowflake 提出了一個叫作 Multi-Cluster Shared-Data 架構。這裏咱們對官方的圖作了一個簡單的微調。oop
接下來咱們以分層的形式來 review 這個架構。從總體上來看,它的結構大體分爲三個層次。
接下來一個點是這個架構的高可用。這裏能夠簡單分解爲 2 個方面。第一個是失敗容錯,第二個是在線升級。
首先,做爲一個 SaaS 化的應用,它的容錯性是須要體如今總體架構上。這裏咱們一樣分層來回顧一下。
接下來個人同事(王祥虎)會跟你們介紹這 3 個框架以及它們是如何融合並最終支撐 T3 湖倉一體的實踐。在介紹第二個議題前他會先介紹咱們的主框架,Hudi 和 Kylin 框架,而後再介紹他們三者之間是如何兩兩融合。最後再介紹T3是如何構建湖倉一體的。
首先來了解一下 Hudi 是什麼。Hudi 最初是由 Uber 的工程師爲了知足他們的數據分析需求設計開發的一個數據湖框架。它於 2019 年 1 月份加入到 Apache 孵化器,並於 2020 年 5 月順利畢業,成爲 Apache 的頂級項目。Hudi 的名字來源於 Hadoop Upserts Deletes and Incrementals 的縮寫。也就是說,Hudi 是一個支持插入、更新、刪除、以及增量處理的數據湖框架。除此以外,它還支持事務性 ACID 增量處理、存儲管理和時間管理。Hudi 可以管理雲上超大規模上百 PB 的分析型數據集,對於全部的雲服務都開箱即用,很是的方便,並且已經在 Uber 內部穩定運行了接近 4 年。
下圖是 Hudi 的插件化架構。咱們能夠看到,Hudi 在存儲、數據處理引擎、表類型、索引類型、查詢視圖和查詢引擎方面都有比較寬鬆的支持。也就是說,他不與某一個組件綁定。
Hudi 支持 3 種查詢,讀優化查詢,增量查詢和快照查詢。而在查詢引擎方面,有 Spark 、Presto、Hive 和 Impala,實際上一些其餘的組件已經支持了。
下面詳細的介紹一下存儲模式和視圖。
在出行業務中,訂單會有支付長尾的屬性。也就是說一個訂單開始以後,它的支付環節可能會拖的比較久。換言之,它可能會在這個用戶下一次出行前才進行支付(也或許會更久,甚至永遠不支付)。這種長尾屬性將會致使一個超長的業務閉環窗口,會致使咱們沒法準確預測數據的更新時機。若是存在多級更新的話,鏈路會比較長,更新成本也很是的高。
下圖是咱們的長尾更新引起的冷數據頻繁更新示意圖。左側是業務庫,右側是有依賴關係的 3 張示意表。當業務庫有數據更新時,右側須要更新的數據可能已經歸檔到性能相對較差的設備上,增長數據更新成本。並且若是此次數據更新會引起長鏈路級聯更新的話,這種慢速的 I/O 還會被進一步放大。
數據的可靠性也是數據 ETL 中不可避免的問題。可能因爲機器故障或者計算邏輯致使加工處理的數據失真或者徹底不對,就會給運營的決策形成很大的影響。數字延遲性方面,在基於 Hive 構件的傳統架構中,因爲 Hive 缺乏索引機制,因此數據更新大都會致使數據分區重寫,且沒有辦法原地刪除。其次小文件問題會增長 NameNode 存儲和查詢的負擔,拖慢進程,在必定程度上增長數據延遲性。
咱們再來介紹一下這個 Kylin 框架。相比較 Hudi,你們應該會對 Kylin 相對熟悉一些,它是一個開源的分佈式分析型數據倉庫,可以提供 Hadoop/Spark SQL 之上的數據查詢窗口。最初是由 eBay 開放並貢獻到開源社區,可以在亞秒內查詢巨大的表。它的祕訣其實就是作預計算,針對一個星型拓撲結構數據立方體,預算多個維度組合的度量把結果寫出到輸出表,對外暴露查詢接口實現實時查詢,也就是用空間來換取存取時間。
Kylin 在今年的 9 月份發佈了 4.0 alpha 版本,這是在 Kylin3 以後一個重大架構升級。使用 Parquet 代替 Hbase 存儲,從而提高了文件的掃描性能,也減輕甚至消除了 Hbase 的維護負擔。Kylin4 從新實現 Spark 構建引擎和查詢引擎,使得計算和存儲分離,也更加適用雲原生的技術趨勢。
伴隨 Kylin3.1 發佈,Kylin 與 Flink 就融合已經完成。這個特性是在 2019 年完成的,Kylin 與 Flink 的集成開始於去年 1 月,經過 Flink Batch 實現。關於 Hudi 融合,能夠說 Kylin 和 Hudi 天生就是兼容的,由於 Hudi 能夠將本身暴露成一張 Hive 表,用戶能夠像讀取 Hive 同樣使用 Hudi 的數據,這樣對Kylin會很是友好。由於 Kylin 能夠把 Hudi 當成一張 Hive 表無縫使用數據。Hudi 和 Flink 融合這個特性是我今年對社區的主要貢獻。這個兩張截圖對應 Hudi 和 Flink 融合路上的2個里程碑式的PR。
下面來詳細介紹下 Hudi 和 Flink 融合過程。Hudi 本來只支持 Spark 引擎,因此第一步是將 Hudi 與 Spark 解耦以後再去集成咱們想要的引擎。
解耦的難點在於 Hudi 最初沒有考慮多引擎的支持,因此從數據源讀取數據到最終將數據寫出到 Hudi 表,RDD 無處不在。連普通的工具類都會使用 RDD 做爲基本的操做單元。與 Spark 解耦,咱們評估到他的改動很是的大。其次是 Flink 與 Spark 核心抽象上的差別。Spark 認爲數據是有限的數據集,而 Flink 認爲數據是無界的,是一種數據流。這種抽象上的差別致使咱們很難統一出一個通用的抽象。
此次改動對於 Hudi 來講是傷筋動骨的,所以咱們決定要優先保證原版 Hudi 的功能和性能,固然也犧牲了部分 Flink Stream API。讓 Flink 來操做 list,而用Spark 操做 RDD。這樣就能夠抽取一個泛型出來造成一個統一的抽象層。
抽象原則:
下面說 Flink Client DAG,這裏主要分了 5 部分,
下面是 Flink 更新的代碼示例。左側是原版裏面 HoodieWriteClient 簡化的版本,
能夠看到 insert 函數的入參是 RDD,返回值也是 RDD。右側抽象以後的 abstract 能夠看到它的入參變成了泛型I,返回值變成了 O,有興趣的話你們能夠去了解一下。
下面是咱們對 Flink 如何融合的另一個想法,就是但願作出一個 streaming source,使用 Flink 構建一個完整的從 Hudi 表讀數據,再寫出到 Hudi 表的 ETL 管道。
而後是咱們初步的設想。左側灰色的圖裏面有 5 列的 Hudi 元數據。最左側是 hoodie_commit_time 事務列表。每個 hoodie_commit_time 對應一個事務,每個事務對應一批的數據。每一批數據中的每一條記錄都會有一個提交的序列號,就是第 2 列 hoodie_commit_seqno 序列號。hoodie_commit_time 和 hoodie_commit_seqno 這種映射關係跟 Kafka 中的分區和 offset 的這種映射關係很是相似。後期咱們可能會基於這種特色實現一個 Hoodie Streaming Source。
基於這 3 個框架之間的融合關係,咱們發現分別用於計算、分析、存儲的這 3 個引擎之間是相互兼容的。而且他們可以支持湖倉一體,向雲原生體系靠攏。
最後咱們來看一看 T3 出行是如何構建湖倉一體的。這是咱們 T3 出行車聯網的架構,能夠看到是從底向上,從基礎支持到上層不停的賦能,並與車企的信息系統、國家信息平臺作交互。做爲一家車聯網驅動的出行公司,咱們收集到了人、車、路等相關的數據,每一種數據都有它本身的應用場景, 數據之間並不孤立,相互賦能,共同支持 T3 智慧出行。
這是咱們的存儲和計算分離的數據庫架構,整個架構分爲了兩層,一層是計算層,一層是存儲層。
在當前存儲計算分離的趨勢下,咱們也是以湖存儲爲核心,在它周圍構建了湖加速湖計算、OLAP 分析、交互式查詢、可視化等等一整套的大數據生態體系。
下面是咱們 T3 內部對 Hudi 的幾個應用場景。
近實時的流式數據處理的 Flink UI 界面上能夠看到以前介紹的 DAG 的幾個算子都在裏面,好比 source、instant_generator 等。
這是咱們用 Hudi 構建的增量數據管道。最左側 CDC 數據捕獲以後要更新到後面的一系列的表。有了 Hudi 以後,由於 Hudi 支持索引和增量數據處理,咱們只須要去更新須要更新的數據就能夠了,不須要再像之前那樣去更新整個分區或者更新整個表。