天天看點

kafka:(9) 流式處理

  kafka 一般被認為是一個強大的消息總線,可以傳遞事件流,但沒有處理和轉換事件的能力。 kafka 可靠的傳遞能力讓它成為流式處理系統完美的資料來源。很多基于 kafka 建構的流式處理系統都将 kafka 作為唯一可靠的資料來源,如 apache storm 、 apache spark streaming 、 apache flink 、 apache samza 等。

  從0.10.0版本開始,kafka不僅為每一個流行的流式處理架構提供了可靠的資料來源,還提供了一個強大的流式處理類庫,并将其作為用戶端類庫的一部分,這樣,開發人員就可以在應用程式裡讀取、處理和生成事件,而不需要再依賴外部的處理架構。

一、流式處理

  資料流是無邊界資料集的抽象表示,無邊界意味着無限和持續增長。如果事件流的定義裡沒有提到事件所包含的資料和每秒鐘的事件數量,那麼它就變得毫無意義。

  事件流模型的一些屬性:

事件流是有序的:事件的發生總是有個先後順序。

不可變的資料記錄:事件一旦發生,就不能被改變。

事件流是可重播的:這是事件流非常有價值的一個屬性。可以借助 kafka 來捕捉和重播事件流。

  三種範式比較:

請求與響應:這是延遲最小的一種範式,響應時間處于亞毫秒到毫秒之間,而且響應時間一般非常穩定。這種處理模式一般是阻塞的,應用程式向處理系統送出請求,然後等待響應。在資料庫領域,這種範式就是線上交易處理 ( oltp)。

批處理:這種範式具有高延遲和高吞吐量的特點。處理系統按照設定的時間啟動處理程序,比如每天的下午兩點開始啟動,每小時啟動一次等。它讀取所有的輸入資料(從上一次執行之後的所有可用資料,或者從月初開始的所有資料等),輸出結果,然後等待下一次啟動。

流式處理:這種範式介于上述兩者之間。大部分的業務不要求亞毫秒級的響應,不過也接受不了要等到第二天才知道結果。流式處理是指實時地處理一個或多個事件流。流的定義不依賴任何一個特定的架構、 api 或特性。隻要持續地從一個無邊界的資料集讀取資料,然後對它們進行處理并生成結果,那就是在進行流式處理。重點是,整個處理過程必須是持續的。

  大部分針對流的操作都是基于時間視窗的,比如移動平均數、 一周内銷量最好的産品、系統的 99 百分位,計算股價的 5 分鐘移動平均數等。兩個流的合并操作也是基于時間視窗的,我們會合并發生在相同時間片段上的事件。

視窗的大小。是基于 5 分鐘進行平均,還是 15 分鐘,或者一天。視窗越小,就能越快地發現變更,不過噪聲也越多。視窗越大,變更就越平滑,不過延遲也越嚴重,如果價格漲了,需要更長的時間才能看出來。

視窗移動的頻率(“移動間隔”)。 5 分鐘的平均數可以每分鐘變化一次,或者每秒鐘變化一次,或者每當有新事件到達時發生變化。如果“移動間隔”與視窗大小相等,這種情況被稱為“滾動視窗”。如果視窗随着每一條記錄移動,這種情況被稱為“滑動視窗”。

視窗的可更新時間多長。假設計算了 00:00 到 00:05 之間的移動平均數, 一個小時之後又得到了一些“事件時間”是 00:02 的事件,那麼需要更新 00:00 到 00:05 這個視窗的結果嗎?或者就這麼算了?理想情況下,可以定義一個時間段,在這個時間段内, 事件可以被添加到與它們相應的時間片段裡。如果事件處于 4 個小時以内,那麼就更新它們 ,否則就忽略它們。

二、流式處理的設計模式

  處理單個事件是流式處理最基本的模式。這個模式也叫 map 或 filter 模式,因為它經常被用于過濾無用的事件或者用于轉換事件( map 這個術語是從 map-reduce 模式中來的, map階段轉換事件, reduce 階段聚合轉換過的事件)。在這種模式下,應用程式讀取流中的事件 ,修改它們,然後把事件生成到另一個流上。

  

kafka:(9) 流式處理

  大部分流式處理應用程式關心的是如何聚合資訊,特别是基于時間視窗進行聚合。例如,找出每天最低和最高的股票交易價格并計算移動平均數。要實作這些聚合操作,需要維護流的狀态。在本例中,為了計算每天的最小價格和平均價格,需要将最小值和最大值儲存下來,并将它們與每一個新值進行對比。這些操作可以通過本地狀态(而不是共享狀态)來實作,可以使用 kafka 分區器來確定具有相同股票代碼的事件總是被寫入相同的分區。 應用程式的每個執行個體從配置設定給它們的分區上擷取事件,應用程式的每一個執行個體都可以維護一個股票代碼子集的狀态。

kafka:(9) 流式處理

  本地狀态對按組聚合操作起到很大的作用。但如果需要使用所有可用的資訊來獲得一個結果呢? 例如,假設要釋出每天的“前 10 支”股票,這 10 支股票需要從每天的交易股票中挑選出來。我們需要一個兩階段解決方案。首先,計算每支股票當天的漲跌,這個可以在每個執行個體上進行。然後将結果寫到一個包含了單個分區的新主題上。另一個單獨的應用執行個體讀取這個分區, 找出當天的前 10 支股票。新主題隻包含了每支股票的慨要資訊 ,比其他包含交易資訊的主題要小很多,是以流量很小,使用單個應用執行個體就足以應付。

kafka:(9) 流式處理

  有時候,流式處理需要将外部資料和流內建在一起,比如使用儲存在外部資料庫裡的規則來驗證事務,或者将使用者資訊填充到點選事件當中。很明顯,為了使用外部查找來實作資料填充,可以這樣做:對于事件流裡的每一個點選事件,從使用者資訊表裡查找相關的使用者資訊,從中抽取使用者的年齡和性别資訊,把它們包含在點選事件裡,然後将事件釋出到另一個主題上,這種方式最大的問題在于,外部查找會帶來嚴重的延遲,一般在 5~15ms 之間,外部資料存儲也無法接受這種額外的負載一一流式處理系統每秒鐘可以處理 10~50 萬個事件,而資料庫正常情況下每秒鐘隻能處理 1 萬個事件,是以需要伸縮性更強的解決方案。

  為了獲得更好的性能和更強的伸縮性,需要将資料庫的資訊緩存到流式處理應用程式裡,能夠捕捉資料庫的變更事件,并形成事件流,流式處理作業就可以監聽事件流,并及時更新緩存。

kafka:(9) 流式處理

  如果要連接配接兩個流,那麼就是在連接配接所有的曆史事件一一将兩個流裡具有相同鍵和發生在相同時間視窗内的事件比對起來。這就是為什麼流和流的連接配接也叫作基于時間視窗的連接配接。

kafka:(9) 流式處理

三、kafka streams的架構概覽

  每個流式應用程式至少會實作和執行一個拓撲。拓撲(在其他流式處理架構裡叫作dag,即有向無環圖)是一個操作和變換的集合,每個事件從輸入到輸出都會流經它。拓撲是由處理器組成的,這些處理器是拓撲圖裡的節點(用橢圓表示)。大部分處理器都實作了一個資料操作一一過濾、映射、聚合等。資料源處理器從主題上讀取資料,并傳給其他元件,而資料池處理器從上一個處理器接收資料,并将它們生成到主題上。拓撲總是從一個或多個資料源處理器開始,并以一個或多個資料池處理器結束。

kafka:(9) 流式處理

  streams 通過在單個執行個體裡運作多個線程和在分布式應用執行個體間進行負載均衡來實作伸縮。使用者可以在一台機器上運作 streams 應用,并開啟多個線程,也可以在多台機器上運作streams 應用。不管采用何種方式,所有的活動線程将會均衡地處理工作負載。

  streams 引擎将拓撲拆分成多個子任務來并行執行。拆分成多少個任務取決于 streams 引擎,同時也取決于主題的分區數量。每個任務負責一些分區:任務會訂閱這些分區,并從分區讀取事件資料,在将結果寫到資料池之前,在每個事件上執行所有的處理步驟。這些任務是 streams 引擎最基本的并行單元,因為每個任務可以彼此獨立地執行。

1)運作相同拓撲的兩個任務——每個讀取主題的一個分區

kafka:(9) 流式處理

2)處理任務可以運作在多個線程和多個伺服器上

  開發人員可以選擇每個應用程式使用的線程數。如果使用了多個線程,每個線程将會執行一部分任務。如果有多個應用執行個體運作在多個伺服器上,每個伺服器上的每一個線程都會執行不同的任務。這就是流式應用的伸縮方式:主題裡有多少分區,就會有多少任務。如果想要處理得更快,就添加更多的線程。如果一台伺服器的資源被用光了,就在另一台伺服器上啟動應用執行個體。kafka 會自動地協調工作,它為每個任務配置設定屬于它們的分區,每個任務獨自處理自己的分區,并維護與聚合相關的本地狀态。

kafka:(9) 流式處理

3)處理主題分區事件的兩組任務

  有時候一個步驟需要處理來自多個分區的結果,這樣就會在任務之間形成依賴。例如,在點選事件流的例子裡對兩個流進行了連接配接,在生成結果之前,需要從每一個流的分區裡擷取資料 。streams 将連接配接操作所涉及的分區全部配置設定給相同的任務,這樣,這個任務就可以從相關的分區讀取資料,井獨立執行連接配接操作。這也就是為什麼streams 要求同一個連接配接操作所涉及的主題必須要有相同數目的分區,而且要基于連接配接所使用的鍵進行分區。如果應用程式需要進行重新分區,也會在任務之間形成依賴。

kafka:(9) 流式處理

繼續閱讀