🌐 This page hasn't been translated yet — showing the original Chinese. Translated posts

Kafka:磁碟為王的有狀態叢集

· tech

#infrastructure#kafka

📑 目錄

進入有狀態的重量級,第一個是 Kafka。用體檢表看它,一切都從第②題「狀態」展開——Kafka 的資料(那條可重播的 log)不是抽象概念,它實實在在躺在 broker 的磁碟上。這一個事實,決定了它 infra 面的全部:瓶頸是什麼、怎麼擴、掛了怎麼辦、在 k8s 上怎麼跑。

狀態在磁碟上:磁碟為王

磁碟為王:資料就躺在 broker 磁碟上 Producer Broker 1P0 · leaderappend logon disk Broker 2P0 · followerappend logon disk Broker 3P0 · followerappend logon disk replicate → ISR(3 副本) 瓶頸是磁碟(throughput + 容量),不是 CPU / 記憶體 Kafka 靠 sequential 順序寫 + page cache + zero-copy,讓「磁碟」也能跑很快
每個 topic 切成多個 partition,而每個 partition 就是某台 broker 磁碟上一條 append-only log。為了不怕單機掛掉,每個 partition 有多個副本(replication,通常 3 份):一個 leader 負責讀寫、其餘 follower 同步跟上,三者組成 ISR。關鍵的 infra 認知是——Kafka 的瓶頸是磁碟(throughput 與容量),而它之所以還能這麼快,是靠 sequential 順序寫、page cache、zero-copy 把磁碟的潛力榨到極致。看 Kafka,先看磁碟

這張圖是 Kafka 一切 infra 決策的根。因為資料在磁碟、且要複製多份,所以:容量的瓶頸是磁碟(retention 設多久、多大,直接換算成要幾 TB);HA 靠 replication——一個 broker 掛,它上面 partition 的 leader 由 ISR 中的 follower 接手,而 acks=all + min.insync.replicas=2 決定「幾個副本確認才算寫成功」,那是持久性與可用性之間的取捨旋鈕。這些全是「因為狀態在磁碟上」延伸出來的。

有狀態的代價:擴縮要搬資料,在 k8s 上要 StatefulSet

有狀態最貴的代價,是擴縮。無狀態的東西加一台就能用;但 Kafka 的資料綁在特定 broker 的磁碟上,擴縮就成了「搬資料」的苦工:

有狀態的代價:擴縮要搬資料 + 在 k8s 上跑 難擴難搬 加 broker:不會自動搬舊資料→ 要手動 partition reassignment partition 數 = consumer 平行度上限而且難減少 → 容量與 partition 要「一開始就規劃」 在 k8s 上:StatefulSet + PV kafka-0 kafka-1 kafka-2 PV PV PV 穩定身分 + 各自綁定的磁碟 監控盯:consumer lag、under-replicated 有狀態 = 難擴難搬 → partition 與容量規劃,是「先付的稅」
加一台 broker 不會自動幫你搬舊資料,你得手動做 partition reassignment 把負載挪過去;而 partition 數既是 consumer group 內的平行度上限、又很難事後減少——這些都逼你一開始就把容量與 partition 規劃好。在 k8s 上,因為每個 broker 綁著自己的資料,只能用 StatefulSet 給它穩定身分(kafka-0/1/2)+ 各自的 PV,重啟後還認得自己那顆磁碟——這正是 stateful 工具在 k8s 上的標準長相

容量與監控:盯磁碟、盯 lag、盯副本

Kafka 的體檢,收斂到三個最該盯的地方:

  • 容量:瓶頸幾乎永遠是磁碟retention.ms / retention.bytes 留多久多大,乘上 replication factor,就是你要準備的磁碟總量。磁碟滿了 broker 會出事,所以 retention 要算、要留 buffer。
  • 監控三大指標:consumer lag(消費落後 producer 多少筆——最重要,直接反映「消費者跟不跟得上」)、under-replicated partitions(有副本沒跟上同步 = 你的冗餘正在失效,危險訊號)、磁碟使用率。這三個是我看 Kafka 健康的第一排儀表。
  • 關鍵旋鈕:replication.factor(通常 3)、min.insync.replicas(通常 2)、acksretention.*num.partitions——這些在 Kafka 維運那篇有更細的展開,這裡從 infra 角度知道「它們決定磁碟用量與持久性」就夠。

反思

Kafka 讓我重新認識了「磁碟」

在碰 Kafka 之前,我對磁碟的印象就是「慢」——所以看到「一個把資料全寫進磁碟的訊息系統,還號稱 High-throughput」時,我是不信的。真正理解它怎麼做到的,顛覆了我的直覺:磁碟慢的是隨機讀寫,順序讀寫其實快得驚人,甚至因為有 page cache 幫忙,常常根本沒真的碰到磁碟。Kafka 就是把「只做順序 append」這個限制,變成了效能的來源。這件事給我的啟發遠超過 Kafka 本身——很多「這東西不是很慢嗎」的直覺,其實是把某一種用法的慢,錯當成了本質的慢。搞清楚一個元件「什麼情況快、什麼情況慢」,比記住「它快還是慢」有用得多。

有狀態的代價,全都藏在「搬資料」這三個字裡

從 infra 角度看過 Kafka,我對stateful 那條軸的體會更具體了:有狀態工具的所有麻煩,幾乎都能收斂成一句「資料很難搬」。加機器要搬 partition、縮容要搬走再下線、換 node 要確保資料還在——無狀態的東西「加一台就好」的輕鬆,在這裡通通不成立。這也是為什麼 Kafka 的 partition 與容量必須一開始就規劃:它不像 stateless 服務可以「先隨便開、之後再調」,因為之後調的代價是搬動 TB 級的資料。有狀態系統的規劃,是一種「先付的稅」——你當下多花的心思,是在替未來省下半夜搬資料的痛。

從 infra 看一個工具,才看得到它「真正的形狀」

我以前學 Kafka,學的是 topic、partition、offset 這些概念;但從 infra 角度重看一遍,才真正認識它——它不是一個抽象的「訊息佇列」,而是一叢吃磁碟、綁磁碟、以磁碟為命的有狀態機器。這個視角的轉換,讓很多原本要死記的規則變得理所當然:為什麼要規劃 partition?因為資料難搬。為什麼在 k8s 要 StatefulSet?因為身分要綁磁碟。為什麼監控盯 under-replicated?因為那是冗餘在失效。當你看見一個工具的「狀態長在哪」,它的整個 infra 形狀就跟著浮現了——這正是這個系列想訓練的那雙眼睛。