返回文章列表
rabbitmq

Lazy Queue

說明 Lazy Queue 的運作原理,如何將訊息直接寫入磁碟以減少記憶體壓力,適用於大量訊息堆積的場景

Aaron

Classic queue 在堆積時會拖垮 broker

RabbitMQ 最危險的生產事故之一是訊息堆積:consumer 掛掉、處理變慢、下游不可用時訊息會在 queue 裡累積,然後整個 broker 陷入連鎖反應。理解 lazy queue 之前,要先知道 classic queue 為什麼會出這種問題。

Classic queue 預設策略是盡量把訊息放記憶體。訊息進來放 RAM、consumer 從 RAM 取,吞吐和延遲都最佳;只有當記憶體壓力超過 vm_memory_high_watermark(預設 40% RAM)時才 page out 到磁碟。這在訊息穩定流動時很好——但堆積時會變成陷阱。

場景:consumer 從每秒 1000 筆掉到 100 筆、producer 還是 1000 筆送進來。差額 900 筆/秒累積在 queue,幾分鐘就是幾十萬筆堆在記憶體。觸到 high watermark 後 RabbitMQ 開始 paging,paging 本身要吃 CPU 和 IO 拖慢 broker;再往上壓則觸發 memory alarm整個 broker 停止接收新訊息,所有 producer 被阻塞,連鎖反應擴散到整個系統。

根因是 classic queue 的預設策略針對「小量、穩定流動」最佳化,對「大量、可能堆積」是災難。

Lazy queue:訊息直接寫磁碟

Lazy queue 的策略相反:訊息一進來就寫磁碟,只在 consumer 取時才載入記憶體。無論 queue 裡有 10 萬筆還是 1000 萬筆,記憶體只保留 buffer 與索引,大約幾十 MB。訊息可以堆積到磁碟上限而不影響 broker 記憶體——把問題從「記憶體」轉化成「磁碟空間」,而磁碟大上幾個數量級且容易擴充。

啟用方式

宣告時指定:

await channel.declare_queue(
    "big_backlog",
    durable=True,
    arguments={"x-queue-mode": "lazy"},
)

或用 policy(推薦,不用改程式):

rabbitmqctl set_policy Lazy "^lazy\." \
    '{"queue-mode":"lazy"}' \
    --apply-to queues

已有訊息的 queue 切換 mode 會觸發全部重寫,挑維運時間執行。

兩種模式的取捨

項目Default QueueLazy Queue
入隊速度快(寫 RAM)較慢(寫磁碟)
出隊速度非常快較慢(讀磁碟)
記憶體使用極低
堆積能力受記憶體限制受磁碟限制
Broker 穩定性堆積會拖垮穩如磐石

Lazy queue 的吞吐大約是 default 的一半(例如 default 50k msg/s,lazy 25k~30k msg/s),換來的是堆積時的穩定性。問題從「誰比較好」變成「能不能接受吞吐減半,換堆積穩定性」。

適用與不適用

適合:訊息量可能暴增consumer 速度不穩堆積是正常狀態延遲不敏感。例如促銷突發流量、爬蟲、批次 ETL、AI 推論、影片轉碼、跨夜批次。

不適合:超低延遲(高頻交易、即時排行榜、廣告競價)、訊息量穩定不堆積(用 default 就好)、訊息小又多且每秒極高(磁碟 IOPS 會變瓶頸)。

無法判斷時預設用 lazy。吞吐從 50k 降到 25k 通常不是瓶頸,但穩定性的提升通常是生產環境的救命稻草。

和 Persistent Message 的差別

概念解決的問題訊息放哪?
Persistent MessageBroker 重啟後不丟訊息Flush 到磁碟,但仍在 RAM
Lazy Queue堆積時不爆 RAM直接寫磁碟,幾乎不進 RAM

Persistent message (delivery_mode=2) 是「壞事發生時能還原」,classic queue 預設仍把它放 RAM 優化消費。Lazy queue 則是「平常就放磁碟」的策略。兩者正交,可以同時使用——生產環境建議組合是 delivery_mode=2 + x-queue-mode=lazy + durable + publisher confirms + quorum queue。

和 Quorum Queue 的關係

Quorum queue 天生就內建類似 lazy 的行為:訊息寫到 Raft log(磁碟),記憶體只保留索引與 in-flight。用了 quorum queue 就不需要也不能再設 x-queue-mode=lazy。新專案直接用 quorum queue,一口氣解決 HA 與記憶體穩定性。

注意事項

  • Mode 切換會觸發訊息重寫,挑流量低時段執行。
  • Lazy queue 對磁碟壓力大,HDD 無法應付,必須 SSD 或 NVMe。
  • 單筆處理延遲多幾毫秒到十幾毫秒,超低延遲場景需考量。