優步在Hadoop上做增量處理的案例

OReillyData發表於2016-09-12

編者注:想了解更多關於優步是如何使用Hadoop和Spark的資訊,請查閱Vinoth Chandar在2016年紐約Strata + Hadoop 世界大會上的演講“Big data processing with Hadoop and Spark, the Uber way”。

優步的任務是提供“對每個人來說,在任何地方都可以獲得像自來水一樣可靠的出行服務”。為了履行這一承諾,優步依賴於在每個層面做出資料驅動的決策。大部分的決策都得益於更快的資料處理。例如,使用資料來理解一個地區以便於增加業務,或城市運營團隊對新資料的訪問來運營每個城市。不用說,資料處理系統的選擇和必要的服務水平協議是資料團隊與優步使用者之間日常互動的主題。

在本文中,我想基於在優步建立資料基礎設施的經驗和經歷,討論準實時案例中資料處理系統的選擇。在本文中,我認為通過增加新的增量處理原語到現有的Hadoop技術中,將能以更少的開銷和統一的方式解決很多問題。在優步,我們正在構建相應的系統來解決這裡總結的問題,並且以開放的態度,希望與對這一領域有興趣的、志同道合的組織進行合作。

準實時案例

首先,讓我們定義這類案例。在一些場景裡,長達一小時的延遲是可容忍的,他們在大部分情況下都可以通過在MapReduce/Spark上用傳統的批處理來執行,同時資料一般會向Hadoop/S3上增量新增。與之相反的另一個極端的案例是:需要小於一到兩秒的延遲,通常涉及到將你的資料輸送到一個可擴充套件的鍵值儲存(已經在這個上工作)並且進行查詢。諸如Storm、Spark流處理以及Flink之類的流式處理系統已經相當好地構建了實際可以支援約一到五分鐘延遲的應用。流式系統對於像欺詐檢測、異常檢測或者系統監控這些需要機器快速響應做出的決策或者以盯著計算機螢幕為日常工作的人來說是非常有用的。

這兩個極端之間給我們留下了一個大鴻溝,即從五分鐘到一小時的端到端的處理延遲。在本文裡我將這種情況稱為準實時。大部分準實時案例商業儀表板,或是一些輔助人工決策的應用。下面是一些準實時可能的應用場景:

1.觀察過去X分鐘內儀表板上是否有任何異常;

2.測量過去X分鐘內在網站上執行的試驗進行的如何;

3.商業指標在X分鐘間隔內的更新;

4.對一個機器學習管道在過去X分鐘內進行特徵抽取;

640?wx_fmt=jpeg

圖一:處理延遲的不同著色圖以及相關的典型技術。由Vinoth Chandar提供

通過“迷你”批次進行增量處理

解決準實時案例的選擇是相當開放的。流式處理能夠提供低延遲,並有較為基本的SQL支援能力,但是需要預先定義查詢來達到較好的效果。專有的資料倉儲有許多特性(例如,事務、索引),並且能支援隨機和預定義的查詢,但是這種專有資料倉儲在規模上有限制而且價格昂貴。批處理可以解決大規模資料的場景,並通過Spark SQL/Hive提供成熟的SQL支援。但是這種處理的方式通常會有比較高的延遲。由於各有利弊,最後使用者通常基於可用的硬體和他們組織內部的運維支援的方式來做出選擇。我們將在本文的結論處在回頭來看這些挑戰。

下面我會介紹通過使用Spark/MapReduce而不是執行流式處理任務,以每X分鐘執行迷你批任務的方式來解決準實時場景的一些技術優點。類似於Spark流處理中的微批次(以秒粒度執行操作),迷你批次以分鐘粒度來執行。在本文中,我將通篇使用“增量處理”這一術語來指代這種處理方式。

增加效率

增量的處理迷你批次中的新資料能更加有效地使用組織中的資源。讓我們來舉個具體的例子,我們有一個Kafka事件流以每秒一萬條的速度湧入,我們想要計算過去15分鐘在一些維度上的訊息的數量。大部分流式處理管道使用一個外部結果儲存系統(例如Cassandra, ElasticSearch)來儲存聚合的計數,並讓在YARN/Mesos等資源管理裡的容器持續執行。這在小於五分鐘的延遲視窗的場景下是說得通的。實際上,典型的YARN容器的啟動開銷大約是一分鐘。此外,為了提升寫操作到結果儲存系統上的效能,我們通常進行快取並進行批量更新,這種協議都需要容器持續地執行。

640?wx_fmt=png

圖二: 流式處理引擎和增量迷你批次任務處理的對比。由Vinoth Chandar提供

然而在準實時處理的場景裡,這些選擇可能不是最佳的。為了達到同樣的效果,你可以使用短生命週期的容器並且優化整體的資源利用。在圖二中,流式處理器在15分鐘內執行了六百萬次更新到結果儲存系統上。但是在增量更新模型裡,我們執行一次記憶體中的合併同時僅進行一次更新到結果儲存系統中,這時只會使用資源容器五分鐘。相比實時模式,增量處理模型有三倍的CPU效率提升,在更新到結果儲存的方面有幾個數量級的效率提升。基本上,這種處理方式按需獲取資源,喚醒的間隔足以完成等待的任務,而不用長時間執行,一邊等待任務,一邊吞食CPU和記憶體。

建立在已有的SQL引擎之上

隨著時間的推移,大量SQL引擎在Hadoop/big data領域演進並發展(例如,Hive, Presto, SparkSQL)。它們提供了更好的針對大資料的複雜問題的表達能力。這些系統已經被大規模地部署,並在查詢計劃、執行等方面得到逐步增強。另一方面,流式處理的SQL仍然處於早期階段。通過使用在Hadoop生態圈內已有的、更加成熟的SQL引擎來執行增量處理,我們可以利用他們自身發展過程中形成的堅實基礎。

例如,連線操作在流式處理中是非常棘手的,因為要在視窗間對齊流。在增量處理模型中,這一問題變得更簡單,因為有著相對更長的視窗,這使得有更多的空間讓流在處理視窗中對齊。另一方面,如果正確性更為重要,SQL提供了一個更加簡單的方式來選擇性地擴充套件連線的視窗並且重新處理。

這類SQL引擎的另一個重要進步是對諸如ORC/Parquet等列式檔案格式的支援,這對於分析工作是有著顯著好處的。例如,連線兩個有Avro記錄的Kafka主題將比連線兩個通過ORC/Parquet檔案格式儲存的Hive/Spark的表的開銷大得多。這是因為,對於Avro記錄來說,你最終要反序列化整個記錄,而列式檔案中只需要讀取在記錄中會被查詢所用到的列。如果我們簡單地從一條編碼的Kafka Avro事件中的1000個欄位中投影出10個欄位,我們仍然需要為所有欄位花費CPU和I/O的開銷。列式檔案格式通常可以更為“聰明”地投影到儲存層。

640?wx_fmt=jpeg

圖三:Kafka事件和HDFS上列式檔案,將10個欄位從1000個欄位中投影出來的CPU和I/O開銷的對比。由Vinoth Chandar提供

較少的運動部件

現在被廣泛實現的Lambda架構(一個基於MapReduce 和 Storm 構建的流式處理的應用架構)有兩個模組:速度層和批處理層。它們通常由兩個獨立的實現(從程式碼到基礎設施)來管理。例如,Storm是速度層上的一個熱門選項,而MapReduce可以作為批處理層來提供服務。實際上,人們經常依賴速度層來提供更新的結果(可能並不準確),而一旦資料被認為是完整了之後,通過批處理層在稍後的時候裡來糾正速度層的結果。隨著增量處理的使用,我們有機會以統一的方式在程式碼層面和基礎設施層面來實現Lambda架構。

640?wx_fmt=jpeg

圖四:結果表的計算,背後是一個經由增量處理得到的快速檢視和一個經由批處理得到的更完整的檢視。由Vinoth Chandar提供

上圖中描述的思想相當簡潔。正如我們所說的,你可以使用SQL或者類似Spark這樣的批處理框架來一致地實現你的處理邏輯。結果表增量地被建立,像流式處理那樣在“新資料”上執行SQL來產生一個結果的快速檢視。同樣的SQL可以週期性的被執行在全資料上,來糾正任何不準確的結果(記住,連線操作總是棘手的!),併產生一個更加“完整”的結果的檢視。在這兩種情況下,我們都將使用同樣的Hadoop基礎設施來執行計算,這可以降低總體運營成本和複雜度。

增量處理的挑戰

在羅列了增量處理架構的優點之後,讓我們來討論一下在現在的Hadoop生態系統中實現這一架構時會面臨的挑戰。

完整性和延遲之間的權衡

在計算時,隨著我們在流式處理、增量處理和批處理之間變換,我們面臨著相同的根本權衡。一些應用需要所有的資料,併產生更為完整和準確的結果,而一些則只需要低延遲的資料來產生相對可接受的結果即可。讓我們來看幾個例子。

640?wx_fmt=png

圖五:展示了不同的Hadoop應用對延遲和資料完整性的容忍度。由Vinoth Chandar提供

圖五描繪了一些應用案例,根據它們對延遲和(不)完整性的容忍度來定位。商務儀表盤可以展示不同的粒度的各項指標。它們通常較為靈活,可展示最近時間內不完整但是有較低延遲的資料,並隨著時間變得完整(這也使得它們成為Lambda架構的代表)。對於資料科學或機器學習的案例而言,從輸入的資料中抽取特徵的過程通常延遲較低,而模型用更完整的資料進行自我訓練的延遲較高。其他的例子中,欺詐檢測要求低延遲地處理可獲取的最新資料。而實驗性平臺需要相當的資料量,並以一個相對較低的延遲來保證實驗結果比較新。

最常見的導致不完整的原因是遲到的資料(正如在這篇谷歌雲資料流的簡報中詳細解釋的)。在真實的環境中,遲到的資料可以是基礎設施層存在問題,例如資料中心的連線斷開了15分鐘;或是使用者層面的問題,例如移動應用由於在飛行中不良的連線質量而導致事件的延遲傳送。在優步,我們面臨著十分相似的挑戰,正如我們今年早些時候在Strata + Hadoop World大會所闡述的

為了有效地支援如此多樣的應用集合,程式設計模型需要以一等公民的方式來對待遲到的資料。然而,Hadoop的處理通常是基於在完整資料(例如Hive中的分割槽)上的批處理,有保證完整性的職責,也要完全依賴資料產生者。在如今複雜的資料生態系統裡,這對於單個資料產生者來說職責簡直太多了。大部分產生者最終通過在一個諸如Kafka這樣的儲存系統上使用流式處理來達到較低的延遲,而依賴Hadoop儲存來達到更加“完整”的(重)處理。我們將在下一節對此展開來講。

缺乏用於增量處理的原語

正如在這篇關於流式處理的文章中詳細描述的,事件時間以及其相對的到達時間的定義和遲到資料的處理是低延遲計算中很重要的方面。遲到的資料要求重新計算時間視窗(通常就是Hadoop中的Hive分割槽),儘管這些時間視窗的結果可能已經被計算完成甚至是已經與終端使用者進行過了互動。通常來說,在流式處理世界中這類重新計算是通過使用可擴充套件的鍵值儲存,在記錄/事件層面增量發生的,並針對點查詢和更新進行優化。然而,在Hadoop中,重新計算通常意味著重寫整個(不可變)的Hive分割槽(或者簡而言之是一個HDFS中的資料夾),並且重新計算所有在那個Hive分割槽上已經被消費過的任務。

從延遲和資源利用角度來看,這些操作都是開銷昂貴的。這一開銷通常會級聯地傳導到整個Hadoop的資料流中,最終導致延遲增加了數小時。因此,增量處理需要使得這兩種操作更加得快速,從而使我們可以有效地將改變包含到已有的Hive分割槽中,並且為下游的表資料消費者提供一個僅獲取新改變的資料的方式。

有效地支援增量處理可以分解為以下幾個原語操作:

更新插入:從概念上講,重寫整個分割槽可以被視作一個非常低效的更新插入操作,最終會寫入比進來的資料多得多的資料。因此,對(批量)更新插入的首要支援成為非常的重要工具。事實上,像KuduHive事務等最近的趨勢的確是朝著這一方向發展的。谷歌的Mesa(谷歌的資料倉儲系統)論文也談論了幾項技術,可以被應用到快速資料注入的場景裡。

增量消費:儘管更新插入可以解決快速地向一個分割槽釋出新資料的問題,下游的資料消費者並不知道從過去的哪一個時刻開始哪些資料被改變了。通常,消費者通過掃描整個分割槽/資料表並重新計算所有資料來得知改變的資料,這需要花費相當多的時間和資源。因此,我們也需要一種機制來更加高效地獲取從上次分割槽被消費的時間點開始改變過的資料記錄。有了上面兩種原語操作,你可以通過更新插入一個資料集,然後從中增量消費,並建立(也是增量的)另外一個資料集來支援很多常見的案例。資料投影就是最好理解的案例(如圖六所示):

640?wx_fmt=png

圖六:一個簡單的例子,通過更新插入新的改變到表1(table_1),並通過增量消費建立一個簡單的投影表(projected_table)。由Vinoth Chandar提供

借用Spark流式處理的說法(如,流-資料集連線,流-流連線),我們可以更高效地以較低的延遲來操作簡單的投影和流-資料集連線。甚至是流-流連線也可以增量計算,只不過需要增加一些額外的邏輯來做視窗對齊。

640?wx_fmt=png

圖七:一個更為複雜的例子,將一個事實表連線到多個維度表,從而建立一個連線過的表。由Vinoth Chandar提供

這個案例是我們可以節省硬體花費的同時顯著地降低延遲的不多見的場景之一。

思維模式的轉變

最後的挑戰嚴格來說並不是技術上的。在選擇技術以應對不同的場景時,組織生態扮演著核心角色。在很多組織中,團隊挑選那些在行業流行的模板化解決方案,並逐步習慣以特定的方式來使用這些系統。例如,典型的資料倉儲的延遲需求是以小時計的。因此,即使底層技術可以在更低的延遲下解決不少問題,但是還是需要花費大量的功夫去實現資料倉儲系統的最小化停機時間或者避免在維護過程中服務中斷。如果你是在建立滿足更低延遲的服務水平協議的系統,這些運維特點是很重要的。另一方面,能解決低延遲問題的團隊也非常擅長運維那些有嚴格服務水平協議要求的系統,這就導致組織機構最後總是會為批處理和流式處理分別建立資料貯藏庫。這就阻礙了在諸如Hadoop的系統上實現增量處理,從而無法獲得上述的好處。

這絕不是要嘗試來泛化組織生態的挑戰。作為一個經歷了推動領英的線上服務,以及推動了優步資料生態系統的人,這些僅僅是我自己的觀察。

可帶走的經驗

我想要留給你以下可帶走的經驗教訓:

1.對實際延遲需求有清晰的定義可以幫你節省很多錢。

2.Hadoop可以通過應用支援增量處理的原語來解決很多問題。

3.統一的架構(程式碼和基礎設施)是未來的方向。

在優步,我們有非常直接和可測量的商業目標/動機去解決這些問題。我們正在著手構建一個可以解決這些需求的系統。如果你對專案合作感興趣,請務必聯絡我們。

Vinoth Chandar

Vinoth Chandar目前致力於將Hadoop和Spark帶到優步。在領英,Vinoth Chandar曾領導Voldemort專案,也曾效力於甲骨文,參與伺服器的複製引擎、高效能運算和流式計算。


歡迎關注OReillyData公眾號,閱讀更多強文。

640?wx_fmt=jpeg



相關文章