kafka:(9) 流式處理


  Kafka 一般被認為是一個強大的消息總線,可以傳遞事件流,但沒有處理和轉換事件的能力。 Kafka 可靠的傳遞能力讓它成為流式處理系統完美的數據來源。很多基於 Kafka 構建的流式處理系統都將 Kafka 作為唯一可靠的數據來源,如 Apache Storm 、 Apache Spark Streaming 、 Apache Flink 、 Apache Samza 等。

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

一、流式處理

1、數據流(也被稱為“事件流”或“流數據”)

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

  事件流模型的一些屬性:

  • 事件流是有序的:事件的發生總是有個先后順序。
  • 不可變的數據記錄:事件一旦發生,就不能被改變。
  • 事件流是可重播的:這是事件流非常有價值的一個屬性。可以借助 Kafka 來捕捉和重播事件流。

2、流式處理

  三種范式比較:

  • 請求與響應:這是延遲最小的一種范式,響應時間處於亞毫秒到毫秒之間,而且響應時間一般非常穩定。這種處理模式一般是阻塞的,應用程序向處理系統發出請求,然后等待響應。在數據庫領域,這種范式就是線上交易處理 ( OLTP)。
  • 批處理:這種范式具有高延遲和高吞吐量的特點。處理系統按照設定的時間啟動處理進程,比如每天的下午兩點開始啟動,每小時啟動一次等。它讀取所有的輸入數據(從上一次執行之后的所有可用數據,或者從月初開始的所有數據等),輸出結果,然后等待下一次啟動。
  • 流式處理:這種范式介於上述兩者之間。大部分的業務不要求亞毫秒級的響應,不過也接受不了要等到第二天才知道結果。流式處理是指實時地處理一個或多個事件流。流的定義不依賴任何一個特定的框架、 API 或特性。只要持續地從一個無邊界的數據集讀取數據,然后對它們進行處理並生成結果,那就是在進行流式處理。重點是,整個處理過程必須是持續的。

 3、時間窗口

  大部分針對流的操作都是基於時間窗口的,比如移動平均數、 周內銷量最好的產品、系統的 99 百分位計算股價的 5 分鍾移動平均數。兩個流的合並操作也是基於時間窗口的,我們會合並發生在相同時間片段上

  • 窗口的大小。是基於 5 分鍾進行平均,還是 15 分鍾,或者一天。窗口越小,就能越快地發現變更,不過噪聲也越多。窗口越大,變更就越平滑,不過延遲也越嚴重,如果價格漲了,需要更長的時間才能看出來。
  • 窗口移動的頻率(“移動間隔”)。 5 分鍾的平均數可以每分鍾變化一次,或者每秒鍾變化一次,或者每當有新事件到達時發生變化。如果“移動間隔”與窗口大小相等,這種情況被稱為“滾動窗口”。如果窗口隨着每一條記錄移動,這種情況被稱為“滑動窗口”。
  • 窗口的可更新時間多長。假設計算了 00:00 到 00:05 之間的移動平均數, 一個小時之后又得到了一些“事件時間”是 00:02 的事件,那么需要更新 00:00 到 00:05 這個窗口的結果嗎?或者就這么算了?理想情況下,可以定義一個時間段,在這個時間段內, 事件可以被添加到與它們相應的時間片段里。如果事件處於 4 個小時以內,那么就更新它們 ,否則就忽略它們。

二、流式處理的設計模式

1、單個事件處理

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

  

2、使用本地狀態

  大部分流式處理應用程序關心的是如何聚合信息,特別是基於時間窗口進行聚合。例如,找出每天最低和最高的股票交易價格並計算移動平均數。要實現這些聚合操作,需要維護流的狀態。在本例中,為了計算每天的最小價格和平均價格,需要將最小值和最大值保存下來,並將它們與每一個新值進行對比。這些操作可以通過本地狀態(而不是共享狀態)來實現,可以使用 Kafka 分區器來確保具有相同股票代碼的事件總是被寫入相同的分區。 應用程序的每個實例從分配給它們的分區上獲取事件,應用程序的每一個實例都可以維護一個股票代碼子集的狀態。

  

3、多階段處理和重分區

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

  

4、使用外部查找一一流和表的連接

  有時候,流式處理需要將外部數據和流集成在一起,比如使用保存在外部數據庫里的規則來驗證事務,或者將用戶信息填充到點擊事件當中。很明顯,為了使用外部查找來實現數據填充,可以這樣做:對於事件流里的每一個點擊事件,從用戶信息表里查找相關的用戶信息,從中抽取用戶的年齡和性別信息,把它們包含在點擊事件里,然后將事件發布到另一個主題上,這種方式最大的問題在於,外部查找會帶來嚴重的延遲,一般在 5~15ms 之間,外部數據存儲也無法接受這種額外的負載一一流式處理系統每秒鍾可以處理 10~50 萬個事件,而數據庫正常情況下每秒鍾只能處理 1 萬個事件,所以需要伸縮性更強的解決方案。

  為了獲得更好的性能和更強的伸縮性,需要將數據庫的信息緩存到流式處理應用程序里,能夠捕捉數據庫的變更事件,並形成事件流,流式處理作業就可以監聽事件流,並及時更新緩存。

  

5、流與流的連接

  如果要連接兩個流,那么就是在連接所有的歷史事件一一將兩個流里具有相同鍵和發生在相同時間窗口內的事件匹配起來。這就是為什么流和流的連接也叫作基於時間窗口的連接。

  

三、Kafka Streams的架構概覽

1、構建拓撲

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

  

2、對拓撲進行伸縮

  Streams 通過在單個實例里運行多個線程和在分布式應用實例間進行負載均衡來實現伸縮。用戶可以在一台機器上運行 Streams 應用,並開啟多個線程,也可以在多台機器上運行Streams 應用。不管采用何種方式,所有的活動線程將會均衡地處理工作負載。

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

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

  

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

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

  

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

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

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM