您當前的位置:首頁 > 舞蹈

Flink筆記02 | 一文讀懂流式大資料引擎的基礎概念

作者:由 PP魯 發表于 舞蹈時間:2019-09-02

最近我在學習流式計算引擎Flink,正在閱讀Flink的官方文件、一些技術部落格以及《Streaming Processing with Apache Flink》這本書,並試圖將一些知識整理下來,形成一個系列。

第一篇文章中我對新一代大資料處理引擎Flink做了簡單的介紹,包括:批次計算與流式計算的區別、流式計算引擎的重要性,以及Flink相比其他流式計算引擎的優勢。因為Flink效能優秀,解決了之前流式計算引擎的痛點,非常適合電商促銷、風險控制、異常檢測、金融交易等領域,阿里、騰訊、華為、美團、滴滴等大公司為了保證業務的實時性,正在積極將Flink部署在生產環境。

第二篇文章中我演示瞭如何使用Flink實現一個流式WordCount程式,並介紹如何在本地搭建Flink叢集。

本文將介紹一些流式大資料引擎的基本概念,這些概念是入門流式計算的必備基礎,並不侷限於Flink這個框架。

對大資料和人工智慧感興趣的朋友可以新增我的微信:aistevelu,大家一起交流學習。

資料流

資料流就是一個無界(unbounded)的事件序列。事件(Event)可以是監控報警資料、感測器感知資料、信用卡交易、使用者在APP上的行為。。。隨著資料量的爆炸式增長,單臺機器無法處理龐大的資料流,一般需要多臺機器並行地處理,因此需要一種並行的流式計算引擎來對大資料場景下的資料流做處理。

Flink筆記02 | 一文讀懂流式大資料引擎的基礎概念

有界和無界資料 來源:Flink官網

流式計算的衡量指標:延遲和吞吐

在批次計算場景,主要透過一次計算的總時間來評價效能。在流式計算場景,資料來源源不斷地流入系統,計算引擎對每個資料處理地越快越好,計算引擎能處理的資料量越大越好。例如處理實時的Twitter文字資料案例,如果系統只能處理一個人發的Tweet或處理時間長達一天,那說明這個系統非常不靠譜。為了衡量流式計算的“快”和“量”兩方面的效能,一般用延遲(Latency)和吞吐(Throughput)這兩個指標。

延遲 Latency

延遲表示一個事件被系統處理的總時間,一般以毫秒為單位。根據業務應用不同,我們一般關心平均延遲和分位延遲(Percentile Latency)。假設一個煎餅攤就是一個流式計算系統,每個顧客來購買煎餅是它所需要處理的事件,從顧客到達到顧客拿到購買的煎餅並付費離開,就是這個顧客的延遲。如果正趕上了早餐高峰期,顧客極有可能排隊,這個排隊時間也要算在延遲時間中。例如,99分位延遲表示系統處理前99%顧客所需的最長時間,也就是對所有顧客延遲排名後,第99%的那個時間。一般商業系統更關注分位延遲,因為分位延遲比平均延遲能反應出這個系統的一些潛在問題。還是以煎餅攤為例,一般煎餅中都有薄脆,薄脆是單獨製作的,如果薄脆製作的速度跟不上煎餅製作的速度,那在高峰期,將拖慢整個過程的延遲,部分使用者會因為等待時間過久而放棄排隊。

延遲對於很多流式計算非常重要,比如欺詐檢測、告警監控等等。像Flink這樣的流式計算引擎可以將延遲降到毫秒級別,如果用mini-batch的方法處理同樣的問題,很可能是分鐘級到小時級的延遲,因為計算引擎必須等待一批資料達到才開始進行計算。

吞吐 Throughput

吞吐表示一個系統最大能處理多少事件,一般以單位時間處理的事件數量為單位。需要注意的是,吞吐除了與引擎自身設計有關,也與資料來源傳送過來的事件資料量有關,有可能計算引擎的最大吞吐量遠大於資料來源的資料量。比如,煎餅攤可能在早七點到九點的需求最高,很可能出現大量排隊的情況,但另外的時間幾乎不需要排隊等待。假設一天能提供1000個煎餅,服務10個小時,那它的平均吞吐量為100個/小時;僅早上2小時的高峰期就提供了600個煎餅,它的峰值吞吐量是300個/小時。比起平均吞吐量,峰值吞吐量更影響使用者體驗,如果峰值吞吐量低,也會導致使用者等待時間過久而放棄排隊。早高峰時,一般使用者都需要排隊等待,排隊的過程被稱作快取(Buffering)。如果仍然有大量事件進入快取,很可能超出系統的極限,就會出現反壓問題(Backpressure),這時候就需要一些優雅的策略來處理類似問題,否則會造成系統崩潰,使用者體驗極差。

延遲與吞吐

延遲與吞吐其實並不是相互孤立的,他們相互影響。如果延遲高,那麼很可能造成吞吐低,系統處理不了太多事件。為了最佳化這兩個指標,一種辦法是提高煎餅師傅的製作速度,當用戶量大到超過單個煎餅師傅的瓶頸時,接著就需要考慮再增加一個煎餅師傅。這也是當前大資料系統都在採用的並行(parallelism)策略,如果一個機器做不了或做得不夠快,那就用更多的機器一起來做。

資料流圖

資料流圖描述了資料如何在不同的操作間流動。資料流圖一般是一個有向圖,圖中的節點是一個運算元(Operator),表示某種運算,邊表示資料間的相互依賴關係或資料的流動方向。運算元從輸入讀取資料,進行一些計算,接著將計算結果傳送到下一個運算元。Source是所有計算的開始,Sink是所有計算的終點。

Flink筆記02 | 一文讀懂流式大資料引擎的基礎概念

一個解析Twitter標籤的資料流圖邏輯視角 來源:Streaming Processing With Apache Flink

上圖從邏輯角度描述資料的流動,對於一個Twitter資料流,接收輸入源後需要將Twitter文字中的#井號標籤去除,提取關鍵詞,再對關鍵詞做詞頻統計。這樣一個圖並沒有考慮大資料情況下跨計算節點計算的問題,它只是一種處理問題的邏輯思路,因此稱之為邏輯視角。

Flink筆記02 | 一文讀懂流式大資料引擎的基礎概念

資料流圖的物理視角 來源:Streaming Processing With Apache Flink

實現一個能夠處理大資料的分散式系統,需要考慮在多個節點上平行計算。上圖將邏輯視角細化為物理視角。Source發出的資料會兵分兩路,被分配到兩個節點上,在各自節點上進行“Extract hashtags”和“Count”運算。每個“Extract hashtags”和“Count”運算只處理一部分資料。最終資料要聚合到Sink上。

資料交換策略

在物理視角中,我們看到資料經歷了跨節點的資料交換。比如,我們要統計“Flink”這個單詞出現的次數,各個節點可能都會解析出“Flink”這個單詞,但是我們最終要的是所有節點上的“Flink”單詞的總和。因此從“Extract hashtags”到“Count”,發生了資料交換,所有的“Flink”被髮送到第一個節點上,才能做詞頻求和統計。在這個任務中,同一個詞需要交換到同一個節點上,就是一種資料交換。

在流式計算場景,某個節點及節點上的資料通常被稱為分割槽(partition)。

資料交換一般有以下幾種策略。

Flink筆記02 | 一文讀懂流式大資料引擎的基礎概念

資料交換策略 來源:Streaming Processing With Apache Flink

Forward:資料在一個分割槽上前向傳播,無需跨節點通訊。

Broadcast:將資料傳送到所有分割槽上,需要大量的跨節點通訊開銷。

Key-Based:按照某個key將資料做分片,某個key的所有資料都會分配到一個分割槽上。剛才詞頻統計的例子中,就是以單詞為key進行的分片處理。

Random:將資料做隨機均勻分片,以避某個分割槽上的資料過大。

狀態 State

狀態是流式計算特有的概念。比如剛才計算詞頻的例子,要統計實時資料流一分鐘內的單詞詞頻,一方面要處理每一瞬間新流入的資料,另一方面要儲存之前一分鐘內已經進入系統的單詞詞頻。再舉一個告警的例子,當系統在監聽到“高溫”事件後10分鐘內又監聽到“冒煙”的事件,系統必須及時報警,系統必須把“高溫”的事件作為狀態記錄下來,並判斷這個狀態下十分鐘內是否有“冒煙”事件。

Flink筆記02 | 一文讀懂流式大資料引擎的基礎概念

無狀態運算元 來源:Streaming Processing With Apache Flink

上圖中的圓圈就是一個無狀態運算元,它將每個輸入方框都轉化成黑色。

Flink筆記02 | 一文讀懂流式大資料引擎的基礎概念

有狀態運算元 來源:Streaming Processing With Apache Flink

上圖的圓圈是一個有狀態運算元,計算的是一個數據流中的最小值。它需要儲存一個當前的最小值作為狀態,並根據新事件來不斷更新這個狀態。

流式計算要處理無界的資料流,要注意如果將這些狀態不斷增長,最後造成資料爆炸,因此會使用一些機制來限制狀態的資料總量。

綜上,實現一個流式計算系統非常複雜,需要考慮幾個因素:

系統必須能有效管理狀態。因為一般的計算既依賴當前事件,也依賴之前事件產生的狀態。

設計能夠管理狀態的並行演算法極具挑戰。一般將資料按照某個key進行切片,將一組大資料切分成小的分割槽,每個分割槽單獨維護狀態資料。

當系統出現錯誤而掛掉重啟時,必須能夠保證之前儲存的狀態資料也能恢復,否則重啟後很多計算結果有可能是錯誤的。一般使用checkpoint來解決這個問題。

可見,流式計算系統比批次計算系統更難實現。

視窗

我們一般要對流式資料以視窗的形式做聚合統計分析。一般有如下幾種定義視窗的方式。

Tumbling

Flink筆記02 | 一文讀懂流式大資料引擎的基礎概念

Count-Based Tumbling Window 來源:Streaming Processing With Apache Flink

Flink筆記02 | 一文讀懂流式大資料引擎的基礎概念

Time-based Tumbing Window 來源:Streaming Processing With Apache Flink

Tumbling視窗互不重疊且一般是定長的,可以是固定事件數目,也可以是固定時間間隔。

Sliding

Flink筆記02 | 一文讀懂流式大資料引擎的基礎概念

Sliding Window 來源:Streaming Processing With Apache Flink

滑動視窗的視窗與視窗之間有滑動間隔(Slide)。

Session

Session是一個使用者與網際網路應用互動的概念,一般指使用者在APP或網站上的一系列行為。比如,使用者在淘寶上短時間有大量的搜尋和點選的行為,這一些列行為組成了一個Session,接著可能因為一些其他因素,使用者暫停了與APP的互動,過一會使用者又返回了APP,經過一系列搜尋、點選、與客服溝通,最終下單。Session視窗的長度並不固定,因此不能簡單用上面兩種形式的視窗來建模。

Flink筆記02 | 一文讀懂流式大資料引擎的基礎概念

Session Window 來源:Streaming Processing With Apache Flink

Session視窗沒有固定長度,一般使用Session Gap將資料做分組。

並行物理視角

Flink筆記02 | 一文讀懂流式大資料引擎的基礎概念

Parallel Count-based Tumbling Window 來源:Streaming Processing With Apache Flink

前面講的幾種視窗都是從全域性視角定義的邏輯視窗,實際上資料是在不同分割槽上的。例如,接受一個感測器資料流,我們可以根據感測器id作為key,將來自同一個感測器的事件都切分到一個分割槽上。每個分割槽的資料是獨立的,其視窗策略也是獨立的。例如上圖所示的,同一顏色的事件被分到同一個分割槽上,組成固定長度為2的視窗。

時間語義

“一分鐘”真的是一分鐘嗎?

你可能覺得時間是最簡單不過的事情,沒什麼可討論的,恰恰相反,在很多應用場景,時間有著不同的意義。“一分鐘”真的是一分鐘嗎?

Flink筆記02 | 一文讀懂流式大資料引擎的基礎概念

穿越隧道的一分鐘 來源:Streaming Processing With Apache Flink

假設你坐高鐵並玩王者榮耀消磨時間,王者榮耀在最終計算MVP時,要考慮的一個因素是玩家每分鐘釋放技能次數。在一波團戰中,你瘋狂搶了三個人頭,正當你覺得穩拿MVP時,高鐵穿越進了隧道,手機丟失訊號,你掉線了!好在高鐵在隧道里只停留了幾十秒,APP快取了你掉線時的資料,並在訊號恢復後將快取資料傳回了伺服器。在這種情形下,時間比想象中更復雜,有一個時間記錄事件實際發生的時間(Event Time),還有一個時間是事件上傳到伺服器後,伺服器處理時間(Processing Time)。

比如,你旁邊的小夥伴跟你一起開黑,他的手機運營商更給力,進隧道後沒有丟訊號,如果都使用Processing Time,在丟失訊號的這段時間,你的資料沒有計算進去,顯然對你來說是不公平的。但是當訊號恢復,資料重傳到伺服器,再根據Event Time重新計算一次,那就非常公平了。我們可以根據Event Time復現一個事件序列的順序,因此,使用Event Time是最準確的。

Watermark

雖然使用Event Time更準確,但問題在於,因為各種不可控因素,事件上報會有延遲,那麼最多要等待多長時間呢?從伺服器的角度來看,在事件到達之前,我們也無法確定是否有事件已經延遲,如何設定Event Time時間視窗成了很大的問題。比如剛才的例子,我們要統計一分鐘內的實時資料,考慮到事件的延遲,如何設定合理的等待時間,以等待一分鐘內所有事件都到達伺服器?也正因為這個問題,流式計算比批次計算在準確性上有差距,因為批次計算一般以更長的一段時間為一個批次,一個批次內延遲上報的資料比一個時間視窗內延遲上報的資料相對比例更少。比如某個電商平臺上,去計算一件商品每分鐘點選次數,使用一天的總數除以分鐘數的計算方法,比使用一分鐘時間視窗實時的點選次數更準確。可以看到,資料的實時性和準確性二者不可得兼,必須取一個平衡。

Watermark是一種折中解決方案,它假設某個時間點上,不會有比這個時間點更晚的上報資料。當運算元接受到一個Watermark後,它會假定後續不會再接收到這個時間視窗的內容,然後會觸發對當前時間視窗的計算。比如,一種 Eager Watermark 策略的等待延遲上報的時間非常短,這樣能保證低延遲,但是會導致錯誤率上升。在實際應用中,Watermark設計多長非常有挑戰。還是以剛才手機遊戲的例子,系統不知道玩家這次掉線的原因是什麼,可能是在穿越隧道,也可能是坐飛機進入飛航模式,還有可能把這個遊戲刪了再也不玩了。

Processing Time 與 Event Time

那既然Event Time似乎可以解決一切問題,為什麼還要使用Processing Time?前面也提到了,為了處理延遲上報或順序錯亂的事件,需要使用一些機制來做等待,這樣會導致延遲上升。在某些場景可能對準確性要求不高,但是要求實時性更高,Processing Time就更合適一些。

投遞保障

事件進入到計算引擎,如果引擎遇到故障並重啟,該事件是否被成功處理了呢?一般有三種結果。

At Most Once

每個事件最多被處理一次,也就是說,有可能某些事件沒有被處理。

At Least Once

每個事件至少被處理一次,如果系統遇到故障,系統重啟後該事件會被再次處理一次。

Exactly Once

每個事件只被處理一次,無論是否有故障重啟。“Exactly Once”意味著事件不能有任何丟失,也必須保障狀態也“Exactly Once”。Flink實現了“Exactly Once”語義。

小結

本文簡述了流式大資料處理引擎的一些基礎概念,包括資料流、資料流圖、衡量指標、狀態、時間、以及投遞保障,每個流式計算引擎的實現過程都要面對這些問題,Flink對這些問題做出了具體實現。

標簽: Flink  流式  計算  延遲  資料