目錄
Flink 流處理(Streaming) & 批處理(Batch)
瀏覽完Flink基礎教程&入門實踐後對Flink有了一個簡單的瞭解,梳理下主要內容知識點
爲何選擇Flink & 爲何不選擇Flink (洗腦洗腦)
Flink概述
Flink 是爲分佈式、高性能、隨時可用以及準確的流處理應用程序打造的開源流處理框架。特性如下:
1、流式優先:可以連續處理流式數據;
2、容錯:提供有狀態的計算,可以記錄數據的處理狀態,當數據處理失敗時,能夠無縫地從失敗中恢復,並保持Exactly-Once;
3、可伸縮:分佈式集羣
4、性能:高吞吐、低延遲。即支持快速地處理海量數據,高吞吐標識單位時間內可以處理的數據量很大,低延遲表示數據產生後在很短的時間內就能將其處理完畢。
Flink架構&基本組件分析
Flink技術棧有四個核心組成部分,分別爲Deploy層、Core層、API層和Library層。
Deploy層:主要涉及Flink的部署模式,Flink支持多種部署模式。eg:本地、集羣等;
Core:提供了支持Flink計算的全部核心實現,爲API層提供基礎服務;
API層:Flink 分別提供了面向流處理的接口(DataStream API)和麪向批處理的接口(DataSet API),(流&批統一:Flink 將批處理(即處理有限的靜態數據)視作一種特殊的流處理);
Library層:Flink應用框架層,支持的拓展庫涉及機器學習(FlinkML)、複雜事件處理(CEP),以及圖計算(Gelly),還有分別針對流處理和批處理的Table API;
另外在Flink中還提供了以下3個組件:
DataSource:表示數據源組件,主要用來接收數據,目前官網提供了readTextFile、socketTextStream、fromCollection以及一些第三方的Source。
Transformation:表示算子,主要用來對數據進行處理,比如Map、FlatMap、Filter、Reduce、Aggregation等。
DataSink:表示輸出組件,主要用來把計算的結果輸出到其他存儲介質中,比如writeAsText以及Kafka、Redis、Elasticsearch等第三方Sink組件。
Flink Job = DataSource + Transformation + DataSink
Flink 流處理(Streaming) & 批處理(Batch)
Flink 是如何同時實現批處理與流處理的呢?
答案是,Flink 將批處理(即處理有限的靜態數據)視作一種特殊的流處理。即流批統一。(NP~~~)
如何有效地實現流處理架構並從 Flink 中獲益呢?
一個常見的做法是設置消息傳輸層和流處理層
(1) 消息傳輸層從各種數據源(生產者)採集連續事件產生的數據,並傳輸給訂閱了這些數據的應用程序和服務(消費者)。
(2) 流處理層有 3 個用途:①持續地將數據在應用程序和系統間移動;②聚合並處理事件;③在本地維持應用程序的狀態。
消息傳輸層:從各個數據生產者中採集連續事件的數據,並傳輸給訂閱了這些數據的消費者,常見的消息傳輸層技術有Kafka和MapR Streams.
這一層中維護了一個事件數據的安全隊列,產生的消息可以被保留起來,也可以重播給流處理層。在複雜系統中,消息傳輸層往往對應了多個生產者與多個消費者,生產者負責生產數據,消費者負責消費數據,兩者相互解耦,即生產者生產消息後,不是由生產者向所有的消費者廣播,而是消費者從消息隊列中訂閱消息,消息到達後,消費者並不一定需要在運行狀態,即消息達到後並不一定立刻被處理,具體處理時間可由消費者根據自身業務邏輯指定。
流處理層:聚合並處理事件;持續地將數據在應用程序與各系統間移動;應用程序的數據狀態本地化。
流式處理計算框架的對比 ?
在大數據處理領域,批處理與流處理一般被認爲是兩種截然不同的任務,一個大數據框架一般會被設計爲只能處理其中一種任務。比如,Storm只支持流處理任務,而MapReduce、Spark只支持批處理任務。Spark Streaming是Apache Spark之上支持流處理任務的子系統,這看似是一個特例,其實不然——Spark Streaming採用了一種Micro-Batch架構,即把輸入的數據流切分成細粒度的Batch,併爲每一個Batch數據提交一個批處理的Spark任務,所以Spark Streaming本質上還是基於Spark批處理系統對流式數據進行處理,和Storm等完全流式的數據處理方式完全不同。
接下來應該是Flink的重要點了,先了解下
Flink 如何有效地準確地進行流處理之對時間的處理
時間概念
在流處理中,主要有3個時間概念,如下:
事件時間:即事件實際發生的時間。更準確的說是每一個事件都有一個與它相關的時間戳,而事件事件其實就是時間戳。
處理時間:即事件被處理的事件。
攝取時間:又稱爲進入時間,即事件進入流處理框架的時間。缺乏真實事件事件的數據會被流處理器附上時間戳,即流處理器第一次看到它的時間。
在Flink中基於時間定義孕育用戶根據所需的語義和對準確性的要求選擇採用事件時間、處理時間或攝取時間定義窗口。
例如: 當採用事件時間定義窗口時,應用程序可以處理亂序事件流以及變化的事件時間偏差,並根據事件實際發生的時間計算出有意義的結果。
窗口?什麼是窗口?
窗口是一種機制,它用於將許多事件按照時間或者其他特徵分組,從而將每一組作爲整體進行分析(比如求和)。
時間窗口:最簡單和最有用的一種窗口。它支持滾動和滑動。舉一個例子,假設要對傳感器輸出的數值求和。
一分鐘滾動窗口的定義:stream.timeWindow(Time.minutes(1))
每半分鐘(即 30 秒)滑動一次的一分鐘滑動窗口定義:stream.timeWindow(Time.minutes(1), Time.seconds(30))
計數窗口:分組依據不再是時間戳,而是元素的數量。滾動和滑動的計數窗口分別定義如下:
stream.countWindow(4)
stream.countWindow(4, 2)
會話窗口:會話指的是活動階段,其前後都是非活動階段,例如用戶與網站進行一系列交互(活動階段)之後,關閉瀏覽器或者不再交互(非活動階段)。會話需要有自己的處理機制,因爲它們通常沒有固定的持續時間(有些 30 秒就結束了,有些則長達一小時),或者沒有固定的交互次數(有些可能是 3 次點擊後購買,另一些可能是 40 次點擊卻沒有購買)。
如果用戶處於非活動狀態長達 5 分鐘,則認爲會話結束。示例如下:
stream.window(SessionWindows.withGap(Time.minutes(5))
觸發器:觸發器控制生成結果的時間,即何時聚合窗口內容並將結果返回給用戶。每一個默認窗口都有一個觸發器。
例如,採用事件時間的時間窗口將在收到水印時被觸發。對於用戶來說,除了收到水印時生成完整、準確的結果之外,也可以實現自定義的觸發器
什麼是時空穿梭?
流處理架構的一個核心能力是時空穿梭(即重新處理數據)。
流處理器支持事件時間,這意味着將數據流“倒帶”,用同一組數據重新運行同樣的程序,會得到相同的結果。
若要按時間回溯並正確地重新處理數據,流處理器必須支持事件時間。
如果窗口的設定是根據系統時間而不是時間戳,那麼每次運行同樣的程序,都會得到不同的結果。事件時間使數據處理結果具有確定性,因爲用同一組數據運行同樣的程序,會得到相同的結果。
如果所有的數據處理工作都由流處理器完成,那麼應用程序如何演進呢?我們如何處理歷史數據,又如何重新處理數據呢?
如圖所示,時空穿梭意味着將數據流倒回至過去的某個時間,重新啓動處理程序,直到處理至當前時間爲止。
像 Kafka 和 MapR Streams 這樣的現代傳輸層,支持時空穿梭,這使得它們與更早的解決方案有所區別。實時流處理總是在處理最近的數據(即圖中“當前時間”的數據),歷史流處理則從過去開始,並且可以一直處理至當前時間。
什麼是水印?
支持事件時間對於流處理架構而言至關重要,因爲事件時間能保證結果正確,並使流處理架構擁有重新處理數據的能力。當計算基於事件時間時,如何判斷所有事件是否都到達,以及何時計算和輸出窗口的結果呢?換言之,如何追蹤事件時間,並知曉輸入數據已經流到某個事件時間了呢?爲了追蹤事件時間,需要依靠由數據驅動的時鐘,而不是系統時鐘。
Flink 通過水印來推進事件時間。
水印是嵌在流中的常規記錄,計算程序通過水印獲知某個時間點已到。假設水印標記時間爲 10:01:00,那麼收到水印的窗口就知道不會再有早於該時間的記錄出現,因爲所有時間戳小於或等於該時間的事件都已經到達。這時,窗口可以安全地計算並給出結果(總和)。
水印使事件時間與處理時間完全無關。遲到的水印(“遲到”是從處理時間的角度而言)並不會影響結果的正確性,而只會影響收到結果的速度。
水印是如何生成的?
在 Flink 中,水印由應用程序開發人員生成,這通常需要對相應的領域有一定的瞭解。
完美的水印永遠不會錯:時間戳小於水印標記時間的事件不會再出現。在特殊情況下(例如非亂序事件流),最近一次事件的時間戳就可能是完美的水印。
啓發式水印則相反,它只估計時間,因此有可能出錯,即遲到的事件(其時間戳小於水印標記時間)晚於水印出現。針對啓發式水印,Flink 提供了處理遲到元素的機制。
設定水印通常需要用到領域知識。
舉例來說,如果知道事件的遲到時間不會超過 5 秒,就可以將水印標記時間設爲收到的最大時間戳減去 5 秒。
另一種做法是,採用一個 Flink 作業監控事件流,學習事件的遲到規律,並以此構建水印生成模型。
水印爲以事件時間說明輸入數據的完整性提供了一種機制,這種機制可能是啓發式的。如果水印遲到得太久,收到結果的速度可能就會很慢,解決辦法是在水印到達之前輸出近似結果(Flink 可以實現)。如果水印到達得太早,則可能收到錯誤結果,不過 Flink 處理遲到數據的機制可以解決這個問題。
上述問題看起來很複雜,但是恰恰符合現實世界的規律——大部分真實的事件流都是亂序的,並且通常無法瞭解它們的亂序程度(因爲理論上不能預見未來)。水印是唯一讓我們直面亂序事件流並保證正確性的機制;否則只能選
擇忽視事實,假裝錯誤的結果是正確的。
Flink 如何有效地準確地進行流處理之有狀態的計算
流式計算分爲無狀態和有狀態兩種情況。
無狀態:觀察每個獨立事件,並根據最後一個事件輸出結果
有狀態:基於多個事件輸出結果,維護了每個獨立事件對輸出結果的狀態(即影響),最終基於最新一個事件與當前狀態輸出結果。
如上圖展示了無狀態流處理和有狀態流處理的主要區別。無狀態流處理分別接收每條記錄(圖中的黑條),然後根據最新輸入的記錄生成輸出記錄(白條)。有狀態流處理會維護狀態(根據每條輸入記錄進行更新),並基於最新輸入的記錄和當前的狀態值生成輸出記錄(灰條)。
Flink如何保證Exactly-Once?
at-most-once:這其實是沒有正確性保障的委婉說法——故障發生之後,計數結果可能丟失。
at-least-once:這表示計數結果可能大於正確值,但絕不會小於正確值。即數程序在發生故障後可能多算,但是絕不會少算。
exactly-once:指的是系統保證在發生故障後得到的計數結果與正確值一致。
Flink 如何保證 exactly-once 呢?它使用一種被稱爲“檢查點”的特性,在出現故障時將系統重置回正確狀態。
什麼是檢查點?
檢查點可以保證Flink實現exactly-once。
檢查點是指每隔一段時間(程序自定義),系統會保存事件的位置以及事件計算的中間狀態,在故障發生重啓後,直接定位到發生故障時事件的位置,並從對應的事件計算的中間狀態開始計算。
如果檢查點保存失敗,Flink會丟棄該檢查點並繼續計算,到下一個檢查點再保存,如果一系列連續的檢查點都失敗,那麼Flink會判斷這個任務是失敗的。
檢查點由 Flink 自動生成,用來在故障發生時重新處理記錄,從而修正狀態。
Flink 檢查點算法的正式名稱是異步屏障快照(asynchronous barrier snapshotting)。該算法大致基於 Chandy-Lamport 分佈式快照算法。
檢查點是 Flink 最有價值的創新之一,因爲它使 Flink 可以保證 exactly-once,並且不需要犧牲性能。
什麼是保存點?
設置好檢查點時間間隔後,檢查點是Flink自動生成的,而Flink提供了用戶可手動觸發狀態保存的接口,那就是保存點,用戶可以通過Flink命令行工具或Web控制檯手動觸發。
保存點與檢查點背後工作方式完全相同。只不過它由用戶通過 Flink 命令行工具或者 Web 控制檯手動觸發,而不由 Flink 自動觸發。和檢查點一樣,保存點也被保存在穩定存儲中。用戶可以從保存點重啓作業,而不用從頭開始。
保存點可以被視爲作業在某一個特定時間點的快照(該時間點即爲保存點被觸發的時間點)。
對保存點的另一種理解是,它在明確的時間點保存應用程序狀態的版本。這和用版本控制系統保存應用程序的版本很相似。
最簡單的例子是在不修改應用程序代碼的情況下,每隔固定的時間拍快照,即照原樣保存應用程序狀態的版本。
更多學習:
https://ververica.cn/developers/flink-basic-tutorial-1-basic-concept/
http://www.imooc.com/article/278651