[軟體概念入門系列] Kafka與Event

Brett Yu
Brett’s dev log
Published in
7 min readNov 4, 2023

本節介紹Kafka基本概念與事件概念

Kafka

Kafka是一個訊息傳遞的分散式系統, 提供高吞吐低延遲的訊息處理平台, 且架構上支援Scale out, 在公司的專案中大量使用, 可以說是公司架構的核心

由於Kafka許多名詞較抽象, 這裡使用YouTube訂閱通知的概念來舉例說明

每個人的YouTube帳號都可以訂閱多個頻道開啟通知, 當頻道管理者上傳新影片時, 系統會通知訂閱者有新影片, 且會記錄使用者是否已閱讀該則通知

而使用者收到通知之後可以選擇做任何該使用者想做的處理, 與其他訂閱同一個頻道的使用者沒有關係:

  • 馬上收看
  • 放到稍後觀看
  • 分享給朋友
  • 其他

接下來以下圖說明Kafka中各個名詞定義

Topic

Kafka中可以使用Topic來區分不同種類的訊息, 如何區分則依照開發人員的設計, 通常會依據資料類型與格式做拆分

如Player存款及提款性質上就有所區分, 內含的欄位也不甚相同, 故可以拆分為兩個不同Topic

Producer

會產生訊息到Topic的應用程式都可稱為Producer, 並不限制只有同一種應用程式可以產生訊息到某個Topic, 比如系統中Wallet用來加款的Topic, 可以由Payment, Marketing等不同來產生訊息

Consumer

Consumer是訂閱Topic的應用程式, 同一個Consumer可以訂閱多個不同Topic, 當Topic有新訊息時會主動通知Consumer, 而Consumer可以有自己獨立的處理邏輯不會互相影響

如Wallet Workrer與Notification Worker都會訂閱Player存款Topic, 當收到存款成功的訊息Wallet Worker會計算等級經驗值, 而Notification Worker會發送即時通知給Portal顯示提示

Message

Kafka中的每則訊息稱之為Message, 而Message會由Key, Value以及timestamp三個部分組成, 通常訊息內容會使用Json格式, 但由於是字串故也可以使用XML, Base64等其他格式, 在寫入Topic後會得到屬於該筆Message的Offset

Consumer Group, Consumer Group Offset與Lag

Consumer在訂閱時使用的識別名稱為Consumer Group, 而Consumer Group目前已讀取到特定Topic的哪一筆訊息稱作Consumer Group Offset, 而所謂的Lag亦即目前Consumer Group Offset距離Topic中的最新資料有多少筆的差距

由於Offset會被保存, 因此當Consumer中斷讀取, 只要用同樣的Consumer Group重新連接就可以由上次的位置繼續讀取

Partition, Rebalance與Scale out

以下仍先舉YouTube的情境來說明:

假設Brett要訂閱某新聞頻道收看所有的新聞影片做期末報告, 但影片數量實在太多, 於是Brett與同學A協調星期一三五日上傳的影片由Brett整理, 星期二四六的影片由同學A負責, 但兩個人會共用同一個YouTube帳號以避免看到重複的影片

當同學A臨時有事無法參與時, 則兩個分組的影片又會暫時回歸到Brett一個人來整理, 直到同學A重新加入

當影片還是太多無法由兩個人消化, Brett又多找了一個同學C, 並將分配改為星期一三, 二四, 五六日共3個組別, 仍是共用同一個YouTube帳號以避免看到重複的影片

以上的範例, 星期一三五日這樣的一個分組可以視為Partition概念, 每則影片都會使用上傳時間的星期幾作為Message Key決定要放到哪一個Partition中, 而每個Partition僅會由同樣Consumer Group中的其中一個Consumer消費, 當有其中一個Consumer異常時, 會進行Rebalance重新分配Partition, 資料量過大時我們可以透過新增Partition的方式來擴展讓更多Consumer可以同時處理

Partition是Message實際存放的地方, 每個Topic都可以設定多個Partition, 而若Producer沒有特別指定Partition, 新產生的Message會依據Key透過演算法決定要落在哪個Partition, 相同的Key必然會儲存在同一個Partition中

同樣Consumer Group中的多個Consumer僅會有其中一個Consumer可以讀取Partition內的資料, 而Consumer Group Offset是針對每個Partition會有不同的記錄

當Consumer數量比Partition少時, 一個Consumer會分配到多個Partition, 而Consumer數量比Partition多時, 就會有Consumer未分配到任何Partition, 當有其中一個Consumer中斷連接時, 所有的Consumer皆會重新分配Partition, 分配後再從該Partition的Offset繼續讀取新資料, 這個行為就稱為Rebalance

交易資料量過大需要Scale out時, Topic可以增加Partition數目, 以讓更多的Consumer可以同時處理資料

訊息順序以及重複訊息

由於Message會依據Key被分配到不同的Partition, 且可能由不同的Consumer消費, 因此在這種情況下不能保證Consumer收到訊息的順序就是真實的順序

若需要保證順序僅能透過相同的Key確保Message進到同一個Partition中, 但仍要考慮可能因為Producer網路問題, 重送等機制造成晚產生的Message先送到Kafka中, 或是有重複訊息存在於Kafka中

由於可能有這類情況, Consumer若是對於資料順序以及重複資料非常敏感, 則必須要自行處理好相關的邏輯

Broker, ZooKeeper

Broker為Kafka Cluster中的單一台Server, 同上面的示意圖, 同一個Topic的不同Partition可能會存放於不同的Broker中

ZooKeeper是不同於Kafka Broker之外的伺服器, 主要負責協助管理Kafka Cluster, 維護Topic, 選出Leader, Consumer Group, Rebalance等等

(在未來的Kafka版本有預計要將ZooKeeper棄用的計畫)

事件驅動設計

訊息的內容是由系統開發者定義, 有些設計訊息種類的方式是依據系統要處理的邏輯, 因此容易造成訊息種類散亂, 邏輯耦合度高, 無法重複利用的問題

而事件驅動設計主要是忠實呈現資料變化的歷程, 並在訊息中涵蓋所有Consumer可能會使用的欄位, 由Consumer自行決定收到訊息後要進行怎麼樣的處理

--

--