打造全球最大規模 Kafka 集羣,Uber 的多區域災備實踐

image

Uber 的 Kafka 生態系統

Uber 擁有世界上最大的 Kafka 集羣,每天處理數萬億條消息和幾個 PB 的數據。如圖 1 所示,Kafka 現在成了 Uber 技術棧的基石,我們基於這個基石構建了一個複雜的生態系統,爲大量不同的工作流提供支持。其中包含了一個用於傳遞來自乘客和司機 App 事件數據的發佈 / 訂閱消息總線、爲流式分析平臺(如 Apache Samza、Apache Flink)提供支持、將數據庫變更日誌流到下游訂閱者,並將各種數據接收到 Uber 的 Hadoop 數據湖中。

image
圖 1:Uber 的 Kafka 生態系統

爲了能夠基於 Kafka 構建一個可伸縮、可靠、高性能、易於使用的消息傳遞平臺,我們克服了許多挑戰。在這篇文章中,我們將着重介紹在進行災難恢復(因集羣宕機導致)時所面臨的一個挑戰,並分享我們如何構建一個多區域的 Kafka 基礎設施。

Uber 的 Kafka 多區域部署

提供業務彈性和連續性是 Uber 的首要任務。我們制定了詳細的災難恢復計劃,儘量減少自然和人爲災難 (如停電、災難性軟件故障和網絡中斷) 對業務的影響。我們採用多區域部署策略,將服務與備份一起部署在分佈式的數據中心中。當一個區域的物理基礎設施不可用時,服務仍然可以在其他區域運行。

我們構建了一個多區域 Kafka 架構,實現了數據冗餘,爲區域故障轉移提供支持。Uber 技術棧中的很多服務都依賴 Kafka 來實現區域級故障轉移。這些服務是 Kafka 的下游,並假定 Kafka 中的數據是可用且可靠的。

圖 2 描繪了多區域 Kafka 架構。我們有兩種集羣:生產者在本地向區域集羣發佈消息,將來自區域集羣的消息複製到聚合集羣,以此來提供全局視圖。爲簡單起見,圖 2 只顯示了兩個區域的集羣。

image
圖 2:兩個區域之間的 Kafka 複製拓撲

在每個區域,生產者總是在本地生產消息,以便獲得更好的性能,當 Kafka 集羣不可用時,生產者會轉移到另一個區域,然後向該區域的區域集羣生產消息。

這個架構中的一個關鍵部分是消息複製。消息從區域集羣異步複製到其他區域的聚合集羣。我們開發了 uReplicator(https://eng.uber.com/ureplicator

——Uber 的 Kafka 數據複製解決方案,健壯且可靠。uReplicator 擴展了 Kafka 的 MirrorMaker,專注於可靠性、零數據丟失保證和易維護性。

從多區域 Kafka 集羣消費消息

從多區域集羣消費消息比生產消息更爲複雜。多區域 Kafka 集羣支持兩種類型的消費模式。

雙活模式

一種常見的類型是雙活(Active/Active)消費模式,消費者在各自區域中消費聚合集羣的主題。Uber 的很多應用程序使用這種模式消費多區域 Kafka 集羣裏的消息,而不是直接連接到其他區域。當一個區域發生故障時,如果 Kafka 流在兩個區域都可用,並且包含了相同的數據,那麼消費者就會切換到另一個區域。

例如,圖 3 顯示了 Uber 的動態定價服務 (即峯時定價) 如何使用雙活模式來構建災備計劃。價格是根據附近地區最近一系列打車數據來計算的。所有的打車事件都被髮送到 Kafka 區域集羣,然後聚合到聚合集羣中。然後,在每個區域,一個複雜的、佔用大量內存的 Flink 作業負責計算不同區域的價格。接下來,一個全活服務負責協調各個區域的更新服務,並分配一個區域作爲主區域。主區域的更新服務將定價結果保存到雙活數據庫中,以便進行快速查詢。

image
圖 3:雙活消費模式架構

當主區域發生災難時,雙活服務會將另一個區域作爲主區域,峯時價格計算會轉移到另一個區域。需要注意的是,Flink 作業的計算狀態規模太大了,無法在區域之間同步複製,因此必須使用聚合集羣的輸入消息來計算其狀態。

我們從實踐中獲得了一個很關鍵的經驗,可靠的多區域基礎設施服務(如 Kafka)可以極大地簡化應用程序針對業務連續性計劃的開發工作。應用程序可以將狀態存儲在基礎設施層中,從而變成無狀態的,將狀態管理的複雜性 (如跨區域的同步和複製) 留給基礎設施服務。

主備模式

另一種多區域消費模式是主備模式(Active/Passive):一次只允許一個消費者 (通過唯一名稱標識) 從一個區域 (即主區域) 的聚合集羣中消費消息。多區域 Kafka 集羣跟蹤主區域的消費進度(用偏移量表示),並將偏移量複製到其他區域。在主區域出現故障時,消費者可以故障轉移到另一個區域並恢復消費進度。主備模式通常被支持強一致性的服務 (如支付處理和審計) 所使用。

在使用主備模式時,區域間消費者的偏移量同步是一個關鍵問題。當用戶故障轉移到另一個區域時,它需要重置偏移量,以便恢復消費進度。由於 Uber 的很多服務不能接受數據丟失,所以消費者無法從高水位 (即最新消息) 恢復消費。另外,爲了避免過多的積壓,消費者也不能從低水位 (即最早的消息) 恢復消費。此外,從區域集羣聚合到聚合集羣的消息可能會變得無序。由於跨區域複製延遲,消息從區域集羣複製到本地聚合集羣的速度比遠程聚合集羣要快。因此,聚合集羣中的消息順序可能會不一樣。例如,在圖 4a 中,消息 A1、A2、B1、B2 幾乎是同時發佈到區域 A 和區域 B 的區域集羣中,但經過聚合後,它們在兩個聚合集羣中的順序是不一樣的。

image
圖 4:a. 跨區域消息複製 b. 消息複製檢查點

爲了管理這些區域的偏移量映射,我們開發了一個複雜的偏移量管理服務,架構如圖 5 所示。當 uReplicator 將消息從源集羣複製到目標集羣時,它會定期檢查從源到目標的偏移量映射。例如,圖 4b 顯示了圖 4a 消息複製的偏移量映射。表的第一行記錄了區域 A 區域集羣的消息 A2(在區域集羣中的偏移量是 1)映射到區域 A 聚合集羣的消息 A2(在聚合集羣中的偏移量是 1)。同樣,其餘行記錄了其他複製路線的檢查點。

偏移量管理服務將這些檢查點保存在雙活數據庫中,並用它們來計算給定的主備消費者的偏移量映射。同時,一個偏移量同步作業負責定期同步兩個區域之間的偏移量。當一個主備消費者從一個區域轉移到另一個區域時,可以獲取到最新的偏移量,並用它來恢復消費。

image
圖 5:偏移量管理服務架構

偏移量映射算法的工作原理如下:在活躍的消費者正在消費的聚合集羣中找到每個區域集羣的最近檢查點。然後,對於每個區域檢查點的源偏移量,找到它們在另一個區域聚合集羣對應的檢查點。最後,在另一個區域的聚合集羣中取最小的那個偏移量。

在圖 6 中,假設活躍消費者目前的進度是區域 B 的 A3 消息(偏移量爲 6)。根據右邊的表檢查點,最近的兩個檢查點分別是偏移量爲 3(藍色) 的 A2 和偏移量爲 5(紅色) 的 B4,分別對應區域集羣 A 中偏移量 1(藍色)和區域集羣 B 的偏移量 3(紅色)。這些源偏移量映射到區域 A 聚合集羣的偏移量 1(藍色) 和偏移量 7(紅色)。根據算法,被動消費者 (黑色) 取兩者中較小的偏移量,即偏移量 1。

image
圖 6:主備消費者從一個區域失效轉移到另一個區域

結論

在 Uber,業務的連續性取決於高效、不間斷的跨服務數據流,Kafka 在公司的災備計劃中扮演着關鍵角色。在這篇文章中,我們簡要地強調了在 Uber 多區域 Kafka 集羣的總體架構,以及當災難發生時不同區域的故障轉移策略。但是,我們還有更具挑戰性的工作要做,目前要解決如何在不進行區域故障轉移的情況下容忍單個集羣故障的細粒度恢復策略。

 

image

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