PB 級數據秒級響應:Uber 實時數據平臺架構演進

引入

Uber 是一家科技公司,在 2010 年初推出了讓司機與乘客便捷溝通的應用軟件,從而改變了出租車市場。爲了支持業務,Uber 積極利用數據分析和機器學習模型輔助運營。從 Uber 乘車的動態定價到外賣軟件 Uber Eats 的 “餐廳經理(Restaurant Manager)” 儀表板,都使用實時數據進行高效操作。在本文中,請跟隨筆者一起了解 Uber 如何管理其支持實時應用程序的基礎架構。

注:本文是筆者閱讀論文 Real-time Data Infrastructure at Uber 後的筆記。

一、背景

Uber 的業務具有高度實時性。數據不斷從多個來源收集:司機、乘客、餐館、食客或後端服務。Uber 處理這些數據以提取有價值的信息,以便爲許多用例做出實時決策,如客戶激勵、欺詐檢測和機器學習模型預測。實時數據處理在 Uber 的業務中扮演着至關重要的角色。該公司使用開源解決方案和內部改進來構建實時基礎架構。

宏觀來看,Uber 的實時數據處理包括三個廣泛領域:

1. 消息平臺: 允許生產者和訂閱者之間的通信。

2. 流處理: 允許將處理邏輯應用於消息流。

3. 在線分析處理(OLAP): 能夠在近乎實時的情況下對所有數據進行分析查詢。

每個領域都面臨着三個基本的擴展挑戰:

二、對基礎架構的要求

Uber 的實時基礎架構需要以下要點:

1. 一致性: 關鍵應用程序需要在所有區域中的數據具備一致性。

2. 可用性: 基礎架構必須具有高度可用性,保證 99.99% 的服務水平。

3. 新鮮度: 大多數用例要求數據具有秒級新鮮度。這確保了對特定事件(如安全事件)做出響應的能力。

4. 延遲: 一些用例需要在原始數據上執行查詢,並要求查詢的 p99 延遲低於 1 秒。

5. 可擴展性: 系統能夠隨着不斷增長的數據量進行擴展。

6. 成本: Uber 需要低成本的數據處理和服務,用以確保高運營效率。

7. 靈活性: Uber 必須提供程序化和聲明式接口,以表達計算邏輯,服務於不同類別的用戶。

三、構建模塊

在這一部分,我們來審視一下 Uber 基礎架構的主要邏輯構建模塊:

四、開源解決方案

接下來的部分將介紹 Uber 採用的開源系統,對應於相應的構建模塊。

Apache Kafka:流存儲

Apache Kafka 是業界廣泛採用的流行開源事件流系統,最初由 LinkedIn 開發,隨後在 2011 年初開源。除性能外,Kafka 被採用的其他因素還包括簡單性、生態系統成熟度和開源社區。

由於 Uber 獨特的規模特性,他們對 Kafka 進行了以下增強:

1)集羣聯邦:邏輯集羣

Uber 開發了一個聯邦化的 Kafka 集羣設置,對生產者和消費者隱藏了集羣細節:

2)死信隊列:失敗消息的隊列

在某些情況下,下游系統無法處理消息(如消息損壞)。最初,有兩種方法可以處理這種情況:

然而,Uber 有許多場景,既不要求數據丟失,也不要求阻塞處理。爲了解決這類用例,Uber 在 Kafka 的基礎上構建了死信隊列(DLQ)策略:如果消費者在重試後無法處理消息,它將把該消息發佈到 DLQ。這樣,未處理的消息將被單獨處理,不會影響到其他消息。

3)消費者代理:中間層

隨着數以萬計的運行 Kafka 的應用程序,Uber 在調試它們和升級客戶端庫方面都面臨挑戰。用戶還在企業內部,使用多種編程語言與 Kafka 交互,這使得提供多語言支持變得十分喫力。

Uber 構建了一個消費者代理層來應對這些挑戰;代理從 Kafka 讀取消息,並將其路由到 gRPC 服務端點。它處理消費者庫的複雜性,應用程序只需採用一個薄型的 gRPC 客戶端。當下遊服務無法接收或處理某些消息時,代理可以重試路由,並在多次重試失敗後將消息發送到 DLQ。代理還能將 Kafka 中的發送機制,從消息輪詢改爲基於推送的消息分派。這提高了消費吞吐量,並允許更多的併發應用程序處理機會。

4)跨集羣複製:集羣間高效複製主題

由於業務規模龐大,Uber 在不同的數據中心使用多個 Kafka 集羣。在這種部署中,Uber 需要 Kafka 的跨集羣數據複製,原因有二:

Uber 構建並開源了一個名爲 uReplicator 的可靠解決方案,用於 Kafka 複製。複製器採用重新平衡算法,在重新平衡的過程中儘可能減少受影響主題分區的數量。此外,它還可以在流量突發時將負載重新分配給備用工作器。

筆者稍微研究了以下 uReplicator 的高層架構,發現了以下內容:

Uber 還開發並開源了另一個名爲 Chaperone 的服務,以跨集羣複製不會造成數據丟失。它收集關鍵統計數據,如每個複製階段的唯一消息數量。然後,Chaperone 比較統計數據,並出現不匹配時生成警報。

Apache Flink:流處理

Uber 使用 Apache Flink 構建了流處理平臺,處理來自 Kafka 的所有實時數據。Flink 提供了一個具有高吞吐量和低延遲的分佈式流處理框架。Uber 採用 Apache Flink 有以下原因:

Uber 對 Apache Flink 做出了以下貢獻和改進:

1)Flink SQL:使用 SQL 構建流式分析應用程序

Uber 在 Flink 的頂層設計了一個名爲 Flink SQL 的層,它可以將 Apache Calcite SQL 輸入轉換爲 Flink 作業。處理器將查詢編譯爲分佈式 Flink 應用程序,並管理其整個生命週期,讓用戶專注於處理邏輯。在幕後,系統將 SQL 輸入轉換爲邏輯計劃,然後通過優化器形成物理計劃。最後,該計劃使用 Flink API 將計劃轉換爲 Flink 作業。

然而,向用戶隱藏複雜性,會增加基礎架構團隊管理生產作業的運營開銷。Uber 不得不應對這些挑戰:

注:Flink SQL 是一個具有無限制輸入和輸出的流處理引擎,它的語義不同於批處理 SQL 系統,如 Presto(稍後將討論)。

2)用於部署、管理和運行的統一架構

Uber 的 Flink 統一平臺實現了分層架構,以提高可擴展性和可擴展性。

得益於這些改進,Flink 已成爲 Uber 的中央處理平臺,負責處理成千上萬的作業。現在,讓我們繼續討論 OLAP 構建模塊的下一個開源系統:Apache Pinot。

Apache Pinot:OLAP 系統

Apache Pinot 是一個開源的分佈式 OLAP 系統,用於執行低延遲的分析查詢。它在 LinkedIn 創建,“因爲工程人員認爲沒有現成的解決方案滿足該社交網站的要求” 之後。Pinot 具有 lambda 架構,可呈現在線(實時)和離線(歷史)數據之間的統一視圖。

自從 Uber 引入 Pinot 以來的兩年時間裏,其數據足跡從幾 GB 增長到數百 TB。隨着時間推移,查詢工作負載從每秒幾百個 QPS(Queries-per-second,每秒查詢數)增加到數萬個 QPS。

Pinot 支持多種索引技術來回答低延遲的 OLAP 查詢,例如倒排索引、範圍索引或星樹索引。Pinot 採用分散 - 收集 - 合併方法,以分佈式方式查詢大型表。它按時間邊界劃分數據,並將數據分組,同時並行執行查詢計劃。以下是 Uber 決定使用 Pinot 作爲其 OLAP 解決方案的原因:

五、用例

在 Uber,用戶利用 Pinot 處理許多實時分析用例。這些用例的主要要求是數據新鮮度和查詢延遲。爲滿足 Uber 的獨特要求,工程師們爲 Apache Pinot 提供了以下功能:

Upsert 操作結合了插入和更新操作。它允許用戶更新現有記錄,並在數據庫中不存在記錄的情況下插入新記錄。Upsert 是許多用例的常見需求,例如更正車費或更新交付狀態。

Upsert 操作的主要挑戰是找到所需記錄的位置。爲了克服這一點,Uber 使用主鍵將輸入流分成多個分區,並將每個分區分發給節點進行處理。這意味着同一個節點將處理具有相同主鍵的所有記錄。Uber 還開發了一種路由策略,將同一分區段上的子查詢路由到同一節點。

Pinot 最初缺乏重要的 SQL 特性,如子查詢和連接。Uber 已將 Pinot 與 Presto 集成,以便在 Pinot 之上啓用標準的 PrestoSQL 查詢。

與數據生態系統的其餘部分集成

Uber 投入了大量精力將 Pinot 與數據生態系統的其餘部分集成,以確保良好的用戶體驗。

例如,Pinot 與 Uber 的模式服務集成,可從輸入 Kafka 主題推斷模式並估計數據的基數。Pinot 還集成了 Flink SQL 作爲數據匯,這樣客戶就可以建立 SQL 轉換查詢,並將輸出信息推送到 Pinot。

1)HDFS:檔案存儲

Uber 使用 HDFS 存儲長期數據,來自 Kafka 的 Avro 格式數據大多以原始日誌的形式存儲在 HDFS 中。壓縮過程將日誌合併成 Parquet 格式,然後可通過 Hive、Presto 或 Spark 等處理引擎使用。該數據集是所有分析目的的真實來源。Uber 還將此存儲用於 Kafka 和 Pinot 中的數據回填。此外,其他平臺也將 HDFS 用於其特定用途。例如:

2)Presto:交互式查詢層

Uber 採用 Presto 作爲其交互式查詢引擎解決方案。Presto 是 Facebook 開發的開源分佈式查詢引擎。它採用大規模並行處理(MPP)引擎,在內存中執行所有計算,避免將中間結果寫入磁盤,從而實現對大規模數據集的快速分析查詢。

Presto 提供了一個帶有高性能 I/O 接口的 Connector API,允許連接到多個數據源:Hadoop 數據倉庫、關係數據庫管理系統(RDBMS)或 NoSQL 系統。Uber 爲 Presto 構建了一個 Pinot 連接器,以滿足實時探索需求。這樣,用戶就可以在 Apache Pinot 上執行標準的 PrestoSQL。

Pinot 連接器需要決定哪些物理計劃的部分可以下推到 Pinot 層。由於 API 的限制,該連接器的第一個版本只包括謂詞下推。Uber 改進了 Presto 的查詢計劃器,並擴展了連接器 API,儘可能多地將運算符下推到 Pinot 層。這有助於降低查詢延遲,充分利用 Pinot 的索引功能。

在瞭解 Uber 如何使用開源系統構建實時基礎架構後,我們將討論 Uber 生產中的一些用例,以及他們如何使用這些系統來實現他們的目標。

3)分析應用:激增定價(Surge Pricing)

激增定價用例是 Uber 中的一種動態定價機制,用於平衡可用司機的供應與乘車需求。用例的總體設計:

4)儀表板:Uber Eats 餐廳經理

Uber Eats 餐廳經理儀表板允許餐廳所有者運行切片查詢,以查看 Uber Eats 訂單的深入分析,如客戶滿意度、熱門菜單項目和服務質量分析。用例的整體設計:

5)機器學習:實時預測監控

機器學習在 Uber 中扮演着至關重要的角色,爲確保模式的質量,監控模型預測輸出的準確性至關重要。用例的總體設計:

6)個例探索:Uber Eats 運營自動化

Uber Eats 團隊需要在來自快遞員、餐廳和食客的實時數據上執行臨時分析查詢。這些洞察將用於基於規則的自動化框架。該框架特別在 COVID-19 期間幫助運營團隊在遵守法規和安全規則的情況下運營業務。用例的總體設計:

在結束文章之前,我將在以下部分提供 Uber 的全面活躍策略,它如何管理數據回填,以及從 Uber 學到的經驗教訓。

全活(all-active)策略:Uber 如何提供業務彈性和連續性

Uber 依靠多地區戰略,確保在地理分佈廣泛的數據中心上運行服務並提供備份。由此,如果一個地區的服務不可用,其他地區的服務仍可正常運行。這種方法的基礎是多地區 Kafka 設置,它提供了數據冗餘和流量延續。

以下是動態定價應用的 active-active 設置示例:

→ 由於 Uber 需要管理每個區域的冗餘管道,因此這種方法需要大量計算。

數據回填

出於多種原因,Uber 需要重新處理舊的數據流:

Uber 使用 Flink 構建了流處理回填解決方案,它有兩種運行模式:

Uber 的經驗教訓

1. 採用開源

Uber 在開源組件上構建了大部分實時分析堆棧,這些開源組件爲 Uber 奠定了堅實的基礎。不過,也遇到了一些挑戰:

2. 系統快速開發和演變

對於 Uber 這樣的大公司來說,在架構演變過程中通常會遇到多種驅動因素,例如新的業務需求或行業趨勢。因此,Uber 認識到了實現快速軟件開發的重要性,以便每個系統都能快速發展:

3. 易於操作和監控

4. 易於用戶入門和調試

Uber 努力解決用戶規模擴展帶來的挑戰,主要改進了以下幾個方面:

結語

Uber 的論文包含了有關實時基礎架構、系統設計以及公司如何改進和調整開源解決方案(如 Kafka、Pinot 或 Presto)以滿足其獨特擴展要求的寶貴經驗。

參考資料

作者丨 Vu Trinh    編譯丨 onehunnit

來源丨 blog.det.life/how-does-uber-build-real-time-infrastructure-to-handle-petabytes-of-data-every-day-ddf5fe9b5d2c

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/3VFbd40kXhmUT_AHrvLdJQ