RabbitMQ:訊息 broker 的叢集與流控
· tech
📑 目錄
收尾「有狀態的重量級」這一批,第三個是 RabbitMQ。它跟 Kafka 都是訊息中介,但 infra 形狀差很多,而差別可以濃縮成一個字:Kafka 是 log,RabbitMQ 是 queue。 這個字的差別,讓它們的狀態、擴展、故障全走向了不同的方向。
log vs queue:一個字的差別,兩種 infra
從 infra 的角度,這個模型差最關鍵的後果是狀態的形狀不同:Kafka 的狀態是一條只增不減、以磁碟 throughput 為王的 log;RabbitMQ 的狀態是一堆 queue 裡「還沒被處理掉」的訊息——它會隨消費而減少、隨 backlog 而膨脹。而正是這個「會膨脹的 queue」,埋下了 RabbitMQ 最招牌的坑。
RabbitMQ 的招牌坑:queue backlog 與 backpressure
RabbitMQ 的頭號故障模式,是 queue backlog——一旦 consumer 跟不上 producer,queue 就會越積越大,而 RabbitMQ 有一套自我保護機制會在此時啟動:
HA、容量、在 k8s 上
- HA:用 quorum queue,別用舊的 mirrored。要讓 queue 本身不因單節點掛掉而丟訊息,現代做法是 quorum queue——底層是 Raft,過半副本確認才算數,取代了舊的 classic mirrored queue(同步慢、故障時可能丟訊息,已被淘汰)。又是共識在真實系統裡的一次現身。
- 容量與擴展:瓶頸是記憶體 + 磁碟(那兩道 watermark)。要注意 queue 本身難水平擴——一個 queue 綁在一個節點上,單 queue 的 throughput 受單節點限制;要更 High-throughput 得靠多 queue 分流,或讓多個 consumer 並行搶同一個 queue(competing consumers)。
- 監控:queue depth(backlog 深度)是第一指標,再來是消費速率、unacked 訊息數、memory/disk alarm 狀態、connection/channel 數。
- 在 k8s 上:跟其他有狀態工具一樣——StatefulSet + PV 放持久化訊息、給 cluster 節點穩定身分互相發現;官方的 RabbitMQ Cluster Operator 幫你管這些。
反思
一個字的模型差,撐開兩套完全不同的 infra
「Kafka 是 log,RabbitMQ 是 queue」——這句話我以前當成一個瑣碎的技術細節,直到從 infra 角度重看,才發現它是一切的分水嶺。留著 vs 拿走,這一個模型上的選擇,像骨牌一樣推倒了後面所有 infra 決策:狀態的形狀(只增的 log vs 會膨脹收縮的 queue)、故障模式(Kafka 是磁碟塞爆 vs RabbitMQ 是 queue backlog backpressure)、擴展方式(Kafka 分 partition vs RabbitMQ 分 queue)。這再次印證了體檢表那個核心信念——看懂一個工具最根本的資料模型,它的整個 infra 形狀就跟著決定了。而反過來,選型時也該從這裡切入:不是問「Kafka 和 RabbitMQ 哪個好」,而是問「我要的是 log 還是 queue」。
好的系統會「保護自己」,而不是硬撐到爆
RabbitMQ 的 backpressure 機制,我一開始覺得很煩——上游好好的怎麼突然寫不進去了?但想通之後反而很欣賞它:一個成熟的系統,在快撐不住的時候,會選擇擋住入口、保護自己,而不是默默吞到記憶體爆掉、整台崩潰。 「寧可拒絕新的、也不讓自己死掉」,這其實跟我在 連鎖失效那篇講的 load shedding、 backpressure 是同一種智慧——過載時主動、優雅地把壓力擋在門外,遠比硬撐到雪崩好。這個觀念我後來套用到很多地方:限流、熔斷、甚至個人的工作量管理——懂得在滿載前說「我先擋一下」,是系統和人共通的成熟。
選型是選「模型」,不是選「誰比較強」
做過這幾篇有狀態工具的對照,我對「技術選型」的理解變得更乾淨了:很多時候,兩個工具不是「一個強一個弱」,而是體現了兩種不同的模型、服務兩種不同的需求。Kafka 和 RabbitMQ 就是最好的例子——它們不是競品,是為不同問題長出來的不同形狀。硬要比「哪個好」,就像問「螺絲起子和鎚子哪個好」一樣沒意義;該問的是「我手上這顆,是螺絲還是釘子」。先把自己的問題看清楚(要 log 還是 queue、要 throughput 還是要路由),答案自己就浮出來了——這比追逐「業界最推薦哪個」有用太多。這也是我做完這批有狀態工具,最想留下的一句話。