iT邦幫忙

2026 iThome 鐵人賽

DAY 1
0

前言

一直以來,只要有有趣的東西推到我面前,我都願意去試一試。今年我參加 COSCUP 的時候,被身邊的講者跟朋友們深深感動。基於好奇,我參加了開源的社群,默默潛水觀察要從哪邊切入


Kafka ? Kaka ?

感謝大佬推薦這個跟我名字只差一個字母的專案,讓我很好奇

這陣子我一邊觀摩大佬修 issue,一邊開始了解這個專案

說實話,我其實沒有很了解 Kafka,但我相信這是上天的旨意要我去認識它 XDDDD


Kafka 介紹整理

以下內容整理自官方入門文件,並且用比喻的方式重新說明:

https://kafka.apache.org/43/getting-started/introduction/


痛點:為什麼會有 Kafka ?

想像一間公司有這些系統:

官網、App、訂單系統、庫存系統、會員系統 ……

現在業務提出一個很合理的需求:

「客人下單之後,庫存要扣、要發通知信、要記一筆帳」

最直覺的做法是:讓訂單系統直接去呼叫其他每一個系統

一開始還好,但系統一多就會變成這樣:

  • 訂單系統要知道所有下游系統的存在、網址、格式、驗證方式
  • 下游任何一個掛掉或變慢,訂單系統就跟著卡住
  • 新增一個「行銷簡訊系統」,就要回去改訂單系統的程式碼

...

這種每個系統互相拉線的狀態,通常被稱為 義大利麵式整合

Kafka 要解決的就是這件事:

不要讓系統互相直接喊話,改成大家把「發生了什麼事」丟到一個中央的地方,有興趣的人自己來拿


從核心觀念「事件」切入

事件(event) 就是一張記錄「某個時間點發生了什麼」的便條紙

它不是「現在的狀態」,而是「發生過的事實」

一個事件長這樣:

欄位 說明 範例
Key(鍵) 這件事跟誰/哪個東西有關 user-8821
Value(值) 到底發生了什麼 付款 200 元給 Bob
Timestamp(時間戳記) 什麼時候發生的 2020-06-25 14:06
Headers(標頭) 附註資訊,選填 來源: iOS App

這裡有個很重要的思維轉換:

  • 傳統資料庫思維:「這位使用者的餘額是 800 元。」(只存現況)

To

  • 事件思維:「他存了 1000、付了 200。」(存發生過的事,現況是算出來的)

第二種寫法多了一個超能力:你可以回頭重播

餘額算錯了?重新跑一次

所謂的事件串流(event streaming),就是把這些便條紙即時收集起來、可靠地存好、可以即時或事後處理、並轉送到需要的地方

官方文件把它比喻為企業的「中樞神經系統」,意思是資訊在系統之間持續流動,而不是每次要用才去問


用一塊佈告欄理解 Kafka

Kafka 像是一面超大的公用佈告欄

  • 有事情發生 -> 寫一張便條紙貼上去
  • 誰想知道 -> 自己去看,而且看完不撕掉,下一個人還能看

這跟傳統訊息佇列的典型用法最大的差別就在這裡:

傳統訊息佇列的典型用法 Kafka
比喻 寄信 貼佈告欄
訊息被處理後 從佇列中移除 還在,別人也能讀
能重讀嗎 通常不行 可以,從任何位置重讀
資料留多久 留到被消費(或 TTL 到期) 自己設定(7 天、30 天、永久都行)

這張表是為了對比而簡化的,別當成絕對。像 RabbitMQ 也可以用 fanout exchange 讓多個佇列各拿一份訊息,近年更推出了 Streams 這種支援保留與重播的佇列型態。差別沒有表上那麼一刀兩斷,只是 Kafka 從第一天就以「留著」為預設。

「看完不刪」這件事聽起來很小,但它是 Kafka 整套設計的關鍵。因為資料還在,所以:

  • 新的系統可以隨時加入,把歷史事件全部補讀一次
  • 程式有 bug 修好之後,可以重跑過去的資料
  • 同一份訂單事件,可以同時被庫存、報表、推薦引擎各自讀取,互不干擾

另外:

Kafka 的讀寫都是循序的,單筆讀寫的效能基本上不隨已存資料量增加而變慢,所以「資料留久一點」不會直接拖慢吞吐

但這不代表零成本:資料量大會拉長故障恢復和擴充時的搬遷時間,而且消費者一旦落後去讀冷資料,就會打到磁碟並影響同一台 broker 上的其他人


核心名詞白話對照

Topic(主題): 分類用的佈告欄

事件不是全部貼在同一面牆上,而是依類型分開

orderspaymentsuser-signups 各一面

官方文件的比喻是「主題像檔案夾,事件像檔案夾裡的檔案」

跟檔案夾不同的是,一個主題可以有任意多個人同時往裡面寫、任意多個人同時讀

Producer(生產者): 貼便條紙的人

任何往 Kafka 寫入事件的程式。例如訂單系統

Consumer(消費者): 看便條紙的人

任何從 Kafka 讀取並處理事件的程式。例如庫存系統、報表系統

這裡有個關鍵設計:生產者和消費者完全不認識彼此。

訂單系統只管貼上去,不需要知道有誰在讀、讀得多快、讀完做什麼

所以下游掛掉不會拖垮上游,新增下游也不用改上游的程式

這叫解耦(decoupling),是 Kafka 能擴充到很大規模的主因之一

Partition(分區): 佈告欄上的「排隊隊伍」

一面佈告欄如果只能一個人貼,就會排隊排到天荒地老

所以 Kafka 把一個主題切成好幾條隊伍(分區),分散在不同機器上,大家可以同時貼、同時讀

隊伍內部是嚴格照順序的,貼上去只能接在最後面(append-only),不能插隊、不能修改

那怎麼決定一張便條要貼進哪條隊伍?看 Key

相同 Key 的事件會被分到同一條隊伍。舉個例子就懂了:

同一個 orders 主題裡,order-99001 的「已建立 -> 已付款 -> 已出貨」三個事件,因為 Key 都是 order-99001,會進同一條隊伍,所以讀的人保證會照這個順序讀到,不會出現「已出貨」跑在「已付款」前面的鬼故事

不過這裡有個前提,我一開始都不知道:

  • 順序只在同一個主題的同一個分區內成立。 如果你把這三個事件拆到 orderspaymentsshipments 三個主題,跨主題就完全沒有順序保證了
  • 分區數不能亂改。 分區的計算方式大致是 hash(key) % 分區數,分區數一調整,同一個 Key 的新事件就可能落到別條隊伍,跟舊事件的順序關係就斷了。這是實務上很有名的坑
  • 沒有 Key 的事件不會集中,而是會被平均分散到各個分區

Offset(位移): 書籤

每條隊伍裡的便條紙都有編號,消費者自己記住「我讀到第 1523 號了」

因為書籤是消費者自己拿的,所以...

想重讀?把書籤往前搬

想從頭來?搬到 0

想只看新的?搬到最後面

Broker(代理節點): 放佈告欄的機房

實際負責存資料、處理讀寫請求的伺服器

一個 Kafka 叢集(cluster) 由一台到很多台 broker 組成,可以橫跨不同機房或雲端區域

小提醒:Kafka 4.x 已經完全移除 ZooKeeper,改用內建的 KRaft 來管理叢集中介資料。網路上很多文章還在教你先裝 ZooKeeper,看到的時候要注意版本

Replication(複製): 影印副本放別的機房

每個分區都可以複製到多台 broker 上,甚至跨機房、跨地理區域

其中一台掛掉,另一台立刻接手。這也讓你可以放心地一台一台重開機做維護

Consumer Group(消費者群組): 分工讀同一面佈告欄

如果事件量太大,一個程式讀不完,可以開幾個實例組成一個群組

Kafka 會自動把分區分配給它們,一人負責幾條隊伍,不會重複讀

順帶一提:群組裡的實例數量超過分區數時,多出來的會閒置。所以分區數是你水平擴充的上限

不同群組之間互不影響

庫存系統群組和報表系統群組各自有自己的書籤,各讀各的。這正是「一份資料餵很多系統」的實作方式


所以,串起來看一遍:一筆訂單的旅程

把上面的名詞放進一個真實流程:

  1. 客人在 App 按下「結帳」
  2. 訂單系統(Producer)產生一個事件,Key 是 order-99001,Value 是訂單內容,寫進 orders 這個 Topic
  3. Kafka 依 Key 把它放進某個 Partition 的尾端,並 複製 到另外兩台 Broker。在 acks=all 的設定下,等副本都寫好才回覆確認,訂單系統收到確認後回覆 App「下單成功」。整件事到這裡結束,訂單系統不需要等任何人
  4. 接下來,各路 Consumer 各自讀:
    • 庫存系統讀到 -> 扣庫存
    • 通知系統讀到 -> 寄確認信
    • 資料倉儲讀到 -> 寫進報表
    • 推薦引擎讀到 -> 更新這位客人的偏好

Kafka 實際提供的能力與工具

官方把 Kafka 的能力歸納成:

  1. 寫入與讀取事件流(含與其他系統之間持續匯入匯出資料)
  2. 持久儲存事件流,要多久都可以
  3. 處理事件流,即時或事後回溯

對應到開發時會用到的 API:

API 白話用途
Producer API 把事件寫進去
Consumer API 把事件讀出來處理
Kafka Streams API 做即時運算:統計、彙總、join、時間視窗(如:「每 5 分鐘各門市的成交金額」)
Kafka Connect API 大多數情況不用寫程式,用設定檔把資料庫、S3、Elasticsearch 等外部系統接上 Kafka
Admin API 管理主題、broker 等

幾個特別值得注意:

  • Kafka Connect:社群已經有數百個現成連接器,例如接 PostgreSQL 就能自動擷取資料表的每一筆變更。實務上你很少需要自己寫連接器(要做客製的資料轉換時還是得動手)
  • Kafka Streams:如果需求是「即時算出某個數字」,這個函式庫可以讓你不用另外架一套運算叢集

它適合用在哪些地方

官方列出的典型情境,共通點都是「資料一直在產生,而且要即時反應」:

  • 金融:證券交易所、銀行、保險的即時交易與付款處理
  • 物流/車聯網:即時追蹤車輛、車隊、貨件位置
  • 製造/IoT:持續蒐集工廠設備、風力發電機的感測器數據
  • 零售/旅宿:即時接收並反應顧客互動與訂單
  • 醫療:監控住院病患狀況、預測病情變化以及時處置
  • 企業內部:打通各部門的資料孤島
  • 技術基礎建設:作為資料平台、事件驅動架構、微服務的底層

接下來來試試

  1. 動手跑一次:照官方 Quickstart 在自己電腦上開一個 Kafka,建立主題、貼幾張便條、讀出來。半小時內能跑完,比讀十篇文章有用
  2. 讀官方文件的 Design 章節:想知道「為什麼它能這麼快」,答案在那裡
  3. 繼續潛水看大佬修 issue,然後找一個看得懂的下手 XDDDD

如果上面有哪裡寫錯了,非常歡迎指正,我還在學


系列文
Offset 人生:從 0 開始消費 Kafka1
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言