Spark權威指南(中文版)----第20章 流處理基礎

Spark The Definitive Guide(Spark權威指南) 中文版。本書詳細介紹了Spark2.x版本的各個模塊,目前市面上最好的Spark2.x學習書籍!!!

掃碼關注公衆號:登峯大數據,閱讀中文Spark權威指南(完整版),系統學習Spark大數據框架!

如果您覺得作者翻譯的內容有幫助,請分享給更多人。您的分享,是作者翻譯的動力

流處理是不斷地合併新數據以計算結果的行爲。在流處理中,輸入數據是無界的,沒有預定的開始或結束。它只是形成一系列到達流處理系統的事件(例如,信用卡交易、網站點擊或來自物聯網(IoT)設備的傳感器讀數)。然後,用戶應用程序可以計算這個事件流上的各種查詢(例如,跟蹤每種事件類型的運行計數,或者將它們聚合到每小時的窗口中)。應用程序將在運行時輸出結果的多個版本,或者可能在外部“接收器”系統(如鍵值存儲)中使其保持最新。

當然,我們可以將流處理與批處理進行比較,批處理中的計算是在固定輸入數據集上運行的。通常,這可能是數據倉庫中的大型數據集,其中包含來自應用程序的所有歷史事件(例如,過去一個月的所有網站訪問數據或傳感器讀數)。批處理也需要一個查詢來計算,類似於流處理,但是隻計算一次結果。

雖然流處理和批處理聽起來不同,但在實踐中,它們常常需要一起工作。爲了處理這些需求,結構化流(Struct Streaming)從一開始就設計了與Spark的其餘部分(包括批處理應用程序)輕鬆地互操作的功能。實際上,結構化流開發人員創造了術語“連續應用程序”來捕獲端到端應用程序,這些應用程序由流、批處理和交互式作業組成,這些作業都在相同的數據上工作,以交付最終產品。結構化流的重點是使以端到端方式構建此類應用程序變得簡單,而不是僅僅處理每條記錄的流級處理。

20.1.流處理場景

我們將流處理定義爲無界數據集的增量處理,但這是激發用例的一種奇怪的方式。在我們討論流處理的優點和缺點之前,讓我們解釋一下爲什麼要使用流處理。我們將描述六個來自底層流處理系統的需求不同的常見用例。

1、通知和預警

最明顯的流用例可能是通知和預警。給定一系列事件,如果發生某種事件或一系列事件,應該觸發通知或警報。這並不一定意味着自主或預先編程的決策;警報還可以用於將需要採取的某些操作通知對應的人員。一個例子可能是向一箇中心的員工發出警報,他們需要從倉庫的某個位置獲取某個物品並將其發送給客戶。在這兩種情況下,通知都需要快速進行。

2、實時報表

許多公司使用流處理系統來運行任何員工都可以查看的實時儀表板。我們使用這些指示板來監控平臺的總體使用情況、系統負載、正常運行時間,甚至在新特性推出時對它們的使用情況。

3、增量ETL

最常見的流應用程序之一是減少公司在將信息重新存儲到數據倉庫時必須忍受的延遲。Spark批處理作業通常用於提取、轉換和加載(ETL)工作負載,這些工作負載將原始數據轉換爲Parquet之類的結構化格式,以支持高效查詢。使用結構化流,這些作業可以在幾秒鐘內合併新數據,使用戶能夠在下游更快地查詢數據。在這個用例中,以容錯的方式精確地處理一次數據是至關重要的: 我們不希望在輸入數據到達倉庫之前丟失任何數據,也不希望加載相同的數據兩次。此外,流系統需要以事務的方式更新數據倉庫,以免將在其上運行的查詢與部分寫入的數據混淆。

4、實時更新數據

流系統經常用於計算由另一個應用程序交互提供服務的數據。例如,像谷歌analytics這樣的web分析產品可能會持續跟蹤每個頁面的訪問次數,並使用流媒體系統來保持這些訪問次數的最新。當用戶與產品的UI交互時,這個web應用程序查詢最新的計數。支持這個用例需要流系統能夠以同步的方式對鍵值存儲(或其他服務系統)執行增量更新,而且通常這些更新是事務性的,就像ETL中的情況一樣,避免破壞應用程序中的數據。

5、實時決策

流系統上的實時決策包括分析新輸入並使用業務邏輯自動響應它們。一個示例用例是,銀行希望根據客戶的近期歷史自動驗證客戶信用卡上的新交易是否代表欺詐,如果費用是預先確定的欺詐金額閾值,則拒絕該交易。這個決策需要在處理每個事務時實時做出,這樣開發人員就可以在流系統中實現這個業務邏輯,並針對事務流運行它。這種類型的應用程序可能需要維護每個用戶的大量狀態,以跟蹤其當前的支出模式,並自動將此狀態與每個新事務進行比較。

6、在線機器學習

實時決策用例的一個密切的派生是在線機器學習。在這個場景中,您可能希望在多個用戶的流數據和歷史數據的組合上訓練模型。一個例子可能比前面提到的信用卡交易用例更復雜:與其根據一個客戶的行爲對硬編碼的規則作出反應,公司可能希望不斷地從所有客戶的行爲更新模型,並根據它測試每個交易。對於流處理系統來說,這是最具挑戰性的用例,因爲它需要跨多個客戶的聚合、針對靜態數據集的連接、與機器學習庫的集成以及低延遲響應時間。

20.2.流處理的優點

現在我們已經看到了流的一些用例,讓我們來明確流處理的一些優勢。在大多數情況下,批處理對於大多數用例來說更易於理解、排除故障和編寫應用程序。此外,批處理數據的能力允許比許多流系統更高的數據處理吞吐量。然而,流處理在兩種情況下是必不可少的。首先,流處理可以降低延遲:當您的應用程序需要快速響應(以分鐘、秒或毫秒爲單位)時,您將需要一個流系統,該系統可以將狀態保存在內存中,以獲得可接受的性能。我們描述的許多決策和預警用例都屬於這個陣營。其次,流處理在更新結果方面也比重複批處理作業更有效,因爲它會自動增加計算量。例如,如果我們希望計算過去24小時內的web流量統計數據,那麼一個天真實現的批處理作業可能在每次運行時掃描所有數據,總是處理24小時的數據。相反,流媒體系統可以記住以前計算的狀態,只計算新數據。例如,如果您告訴流媒體系統每小時更新您的報告,那麼它每次只需要處理1小時的數據(自上次報告以來的新數據)。在批處理系統中,您必須手動實現這種增量計算,以獲得相同的性能,這將導致流系統自動爲您提供大量額外的工作。

20.3.流處理的挑戰

我們討論了流處理的動機和優點,但是您可能知道,天下沒有免費的午餐。讓我們討論在流上操作的一些挑戰。爲了演示這個例子,讓我們假設我們的應用程序從傳感器(例如汽車內部)接收輸入消息,傳感器在不同的時間報告它的值。然後我們希望在這個流中搜索特定的值,或特定的值模式。一個具體的挑戰是輸入記錄可能無序地到達我們的應用程序:例如,由於延遲和重新傳輸,我們可能會按順序收到以下更新序列,其中time字段顯示實際測量值的時間:

{value: 1, time: "2017-04-07T00:00:00"}{value: 2, time: "2017-04-07T01:00:00"}{value: 5, time: "2017-04-07T02:00:00"}{value: 10, time: "2017-04-07T01:30:00"}{value: 7, time: "2017-04-07T03:00:00"}

在任何數據處理系統中,我們都可以構造邏輯來執行一些基於接收單個值“5”的操作。在流媒體系統中,我們還可以快速響應這個單獨的事件。然而,如果您只想根據接收到的特定值序列(比如2、10、5)觸發某個操作,那麼事情就變得更復雜了。在批處理的情況下,這並不特別困難,因爲我們可以簡單地按時間字段對所有事件進行排序,從而看到10確實在2到5之間。然而,這對於流處理系統來說比較困難,原因是流處理系統將單獨接收每個事件,並且需要在事件之間跟蹤一些狀態,以記住2和5個事件,並認識到10個事件介於兩者之間。需要記住流上的這種狀態會帶來更多的挑戰。例如,如果您有大量的數據量(例如,數百萬個傳感器流),而狀態本身是大量的,該怎麼辦?如果系統中的機器發生故障,丟失一些狀態,該怎麼辦?如果負載不平衡,一臺機器運行緩慢怎麼辦? 當對某些事件的分析“完成”時(例如,2-10-5模式沒有發生),您的應用程序如何向下遊消費者發出信號? 它應該等待固定的時間還是無限期地記住某個狀態? 當您想部署流應用程序時,可能會遇到所有這些挑戰和其他挑戰,比如生成系統事務的輸入和輸出。總而言之,我們在前一段和其他幾段中所描述的挑戰如下:

  • 基於應用程序時間戳(也稱爲事件時間)處理無序數據

  • 維持大量的狀態

  • 支持高數據吞吐量

  • 儘管機器出現故障,但每個事件僅處理一次

  • 處理負載不平衡和掉隊

  • 以低延遲響應事件

  • 與其他存儲系統中的外部數據連接

  • 確定在新事件到達時如何更新輸出接收器

  • 以事務方式將數據寫入輸出系統

  • 在運行時更新應用程序的業務邏輯

這些主題都是大型流處理系統研究和開發的活躍領域。爲了理解不同的流處理系統是如何應對這些挑戰的,我們描述了一些常見的設計概念。

20.4.流處理設計中的要點

爲了支持我們描述的流處理挑戰,包括高吞吐量、低延遲和無序數據,有多種方法可以設計流處理系統。我們在這裏描述最常見的設計選項,然後在下一節描述Spark的選擇。

20.4.1.每次一條記錄 API與聲明式API的比較

設計流API最簡單的方法是將每個事件傳遞給應用程序,並讓它使用定製代碼進行響應。這是許多早期流系統(如Apache Storm)實現的方法,當應用程序需要完全控制數據處理時,它具有重要的地位。提供這種"每次一條記錄"API的流只是給用戶一個“管道”集合,以便將它們連接到一個應用程序中。然而,這些系統的缺點是,我們前面描述的大多數複雜因素,如維護狀態,都是由應用程序單獨控制的。例如,對於"每次一條記錄"API,用戶負責在更長的時間內跟蹤狀態,在一段時間後刪除狀態以清空空間,並在失敗後以不同的方式響應重複的事件。正確地爲這些系統編程是相當具有挑戰性的。重要的是,底層api需要具有深入專業知識的人員來開發和維護。

因此,許多較新的流系統提供聲明性api,應用程序在其中指定要計算什麼,而不是如何計算以響應每個新事件,以及如何從失敗中恢復。例如,Spark的原始DStreams API提供了基於流上的map、reduce和filter等操作的功能性API。在內部,DStream API自動跟蹤每個操作符處理了多少數據,可靠地保存了任何相關狀態,並在需要時從故障中恢復計算。谷歌Dataflow和Apache Kafka Streams等系統提供了類似的功能性api。Spark的結構化流實際上進一步擴展了這一概念,從功能操作切換到關係操作(類似sql),這些操作無需編程即可實現更豐富的自動優化執行。

20.4.2.事件時間與處理時間

對於具有聲明性api的系統,第二個問題是系統本身是否支持事件時間。事件時間是基於插入到源記錄中的時間戳來處理數據的概念,而不是基於流應用程序接收記錄的時間(稱爲處理時間)。特別是在使用事件時間時,記錄可能會無序地到達系統,並且不同的源之間也可能不同步(對於相同的事件時間,一些記錄可能比其他記錄晚到達)。如果您的應用程序從可能會延遲的遠程數據源(如移動電話或物聯網設備)收集數據,事件時間處理非常重要:如果沒有事件時間處理,當某些數據延遲時,您將錯過重要的處理模式。相反,如果應用程序只處理本地事件(例如,在同一數據中心中生成的事件),則可能不需要複雜的事件處理。

在使用事件時間時,多個問題成爲應用程序之間的常見問題,包括以一種允許系統合併延遲事件的方式跟蹤狀態,以及確定在事件時間中爲給定時間窗口輸出結果(例如:當系統可能已經接收到所有的輸入到那一時間點)。正因爲如此,許多聲明性系統(包括結構化流)的所有api中都集成了對事件時間的“原生”支持,因此可以在整個程序中自動處理這些問題。

20.4.3.連續處理及微批處理

您經常看到的最終設計決策是關於連續執行還是微批處理執行之間的選擇。在基於連續處理的系統中,系統中的每個節點都在不斷地偵聽來自其他節點的消息,並向其子節點輸出新的更新。例如,假設您的應用程序在多個輸入流上實現了map-reduce計算。在一個連續處理系統中,每個實現map的節點將逐個從輸入源讀取記錄,計算其在這些記錄上的函數,並將它們發送到適當的reducer。reducer程序將在獲得新記錄時更新其狀態。關鍵思想是,這發生在每個單獨的記錄上,如圖20-1所示。

連續處理的優點是,當總輸入速率相對較低時,它提供了儘可能低的延遲,因爲每個節點都會立即響應一條新消息。然而,連續處理系統通常具有較低的最大吞吐量,因爲它們對每條記錄都會產生大量的開銷(例如,調用操作系統向下遊節點發送數據包)。

相比之下,微批處理系統等待積累小批輸入數據(比如500毫秒),然後使用分佈式任務集合並行處理每個批處理,類似於在Spark中執行批處理作業。微批處理系統通常可以實現每個節點的高吞吐量,因爲它們利用了與批處理系統相同的優化(例如,向量化處理),並且不產生任何額外的每個記錄開銷,如圖20-2所示。

因此,它們需要更少的節點來處理相同的數據速率。微批處理系統還可以使用動態負載平衡技術來處理不斷變化的工作負載(例如,增加或減少任務數量)。然而,缺點是由於等待累積微批處理而導致更高的基礎延遲。在實踐中,流應用程序的規模大到需要分發它們的計算,因此傾向於優先考慮吞吐量,因此Spark傳統上實現了微批處理。然而,在結構化流中,有一種積極的開發工作也支持同一API下的連續處理模式。

在這兩種執行模式之間進行選擇時,您應該記住的主要因素是所需的延遲和總操作成本(TCO)。根據應用程序的不同,微批處理系統可以輕鬆地將延遲從100毫秒延遲到每秒。在這種情況下,它們通常需要更少的節點來實現相同的吞吐量,從而降低操作成本(包括由於更少的節點故障而降低的維護成本)。對於低得多的延遲,您應該考慮使用連續處理系統,或者使用微批處理系統與快速服務層結合來提供低延遲查詢(例如,將數據輸出到MySQL或Apache Cassandra,在那裏可以在毫秒內將數據送達客戶機)。

20.5.Spark’s Streaming APIs

我們介紹了一些用於流處理的高級設計方法,但是到目前爲止,我們還沒有詳細討論Spark的api。Spark包括兩個流api,如本章開頭所討論的。Spark流中的早期DStream API是完全面向微批處理的。它有一個聲明性的(基於函數的)API,但是不支持事件時間。新的結構化流API添加了更高級別的優化、事件時間和對連續處理的支持。

20.5.1.The DStream API

Spark最初的DStream API自2012年首次發佈以來,就被廣泛用於流處理。例如,在Datanami 2016年的調查中,DStreams是使用最廣泛的處理引擎。由於Spark的高級API接口和簡單的精確一次語義,許多公司在生產中大規模使用和操作Spark流。Spark流還支持與RDD代碼的交互,比如與靜態數據的連接。操作Spark流並不比操作普通Spark集羣困難多少。然而,DStreams API有幾個限制。首先,它完全基於Java/Python對象和函數,而不是數據框架和數據集中更豐富的結構化表概念。這限制了引擎執行優化的機會。其次,API純粹基於處理時間來處理事件時間操作,應用程序需要自己實現它們。最後,DStreams只能以微批處理方式進行操作,並在其API的某些部分公開微批處理的持續時間,因此很難支持其他執行模式。

20.5.2.Structured Streaming

結構化流是基於Spark的結構化API構建的高級流API。它適用於所有運行結構化處理的環境,包括Scala、Java、Python、R和SQL。與DStreams一樣,它也是一個基於高級操作的聲明性API,但是通過在本書前一部分介紹的結構化數據模型的基礎上進行構建,結構化流可以自動執行更多類型的優化。然而,與DStreams不同,結構化流具有對事件時間數據的原生支持(其所有窗口操作符都自動支持它)。從Apache Spark 2.2開始,系統只在微批處理模型中運行,但Databricks的Spark團隊已經宣佈了一項名爲持續處理的工作,以添加持續執行模式。這應該成爲Spark 2.3中用戶的一個選項。

可以使用Apache Spark輕鬆構建端到端連續應用程序,Apache Spark結合了流、批處理和交互式查詢。例如,結構化流不使用獨立於DataFrames的API:您只需編寫一個普通的DataFrame(或SQL)計算並在流上啓動它。當數據到達時,結構化流將以增量方式自動更新此計算的結果。在編寫端到端數據應用程序時,這是一個主要的幫助:開發人員不需要維護批處理代碼的單獨流版本(可能針對不同的執行系統),而且可能會導致這兩個版本的代碼不同步。另一個例子是,結構化流可以將數據輸出到Spark SQL可用的標準接收器,例如Parquet表,從而可以輕鬆地從另一個Spark應用程序查詢流狀態。在Apache Spark的未來版本中,我們期望越來越多的項目組件與結構化流集成,包括MLlib中的在線學習算法。一般來說,結構化流是Spark streams的DStream API的一種更易於使用和性能更高的改進,因此在本書中我們將只關注這個新API。許多概念,例如用轉換圖構建計算,也適用於DStreams,但是我們將對這些概念的闡述留給其他書籍。

20.6.結論

本章介紹了理解流處理所需的基本概念和思想。本章介紹的設計方法應該闡明如何評估給定應用程序的流系統。您還應該能夠輕鬆地理解DStreams和結構化流的作者所做的權衡,以及在使用結構化流時直接支持DataFrame程序的原因:不需要複製應用程序邏輯。在接下來的章節中,我們將深入研究結構化流來理解如何使用它。

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