🎯 什麼情境該想到我

當你「訊息有時效,過了期限就不該再被處理」的時候。

⚙️ 怎麼用(步驟 / 公式)

意圖:標示訊息在多久後失效,避免接收端處理到過時、無意義的資料。

做法要點:

  • 在訊息標頭設定過期時間(有效期限)。
  • 若訊息在期限內仍未被消費,訊息系統將其作廢。
  • 作廢的訊息通常轉送到 Dead Letter Channel(死信通道),而非交付給接收者。

★ 各家 broker 的 TTL 機制(粒度差很多)

查證 2026-09-25。

broker機制★ 粒度
RabbitMQx-message-ttl(queue 級)、expiration(每則訊息)★ 兩種都有;過期會進 DLX(見下)
SQS訊息 retention★ 只有 queue 級:預設 4 天,最短 60 秒,最長 14 天
Kafkaretention.ms(topic 級)★★ 沒有 per-message TTL;而且它是「保留期」不是「過期」
NATS JetStreamstream 的 max_agestream 級

★★ Kafka 的 retention 不是訊息過期——這是最常見的誤解

★ RabbitMQ 的 TTL:訊息過期 → 對消費者「不可見」(或進 DLX)
★ Kafka 的 retention:★ 到期的是「整個 log segment」,而且是在「清理時」才刪
  → 訊息在 retention 內都會被投遞,包含「業務上已經過期」的
  → ★★ Kafka 不會幫你擋過期訊息。你必須在消費端自己判斷
// ★ Kafka 上必須自己做「業務層過期」
if !e.ExpiresAt.IsZero() && time.Now().After(e.ExpiresAt) {
    metrics.ExpiredMessages.Inc()          // ★ 一定要有指標,否則你不知道在丟東西
    return msg.Ack()                       // ★ 過期就 ack 掉,不要重試
}

★★ RabbitMQ 的兩個陷阱

① ★ queue TTL 是「惰性」的
   x-message-ttl 到期的訊息不會馬上消失 —— 它在「到隊首時」才被判定過期
   → ★ 佇列中間的過期訊息仍佔著空間;而且如果前面卡住,它們會一直留著

② ★★ 整個佇列過期時,裡面的訊息「不會」進 DLX
   (官方文件明說,2026-09-25 查證)
   → ★ 你設了 DLX 也救不到,訊息靜默消失

★★ 最重要的設計問題:過期的語義是什麼

★ 三種完全不同的「過期」,不要混:
① 技術性過期(broker retention):★ 我們不想無限保存訊息
   → 這是容量管理,不是業務規則

② ★ 業務性過期(這則訊息做了也沒意義了)
   「三小時前的限時折扣通知」「已經取消的訂單的出貨命令」
   → ★★ 這必須放在訊息內容裡(ExpiresAt 欄位),由消費端判斷
   → ★ 依賴 broker 的 TTL 來表達業務規則,是把業務邏輯藏進基礎設施設定

③ ★ 請求逾時(我不想等了)
   → 那是請求者端的事(見 [[請求-回覆]] 的 deadline)

★★ 判準:這個時限是「業務規則」還是「容量管理」?
業務規則 → 放在訊息裡(ExpiresAt),讓它可測試、可 code review、進版控。
容量管理 → 放 broker 設定。

★★ 最危險的陷阱:過期的訊息去哪了

① ★ 靜默丟棄(SQS retention、Kafka retention)
   → ★★ 沒有任何指標顯示你丟了東西。這是「資料默默消失」的典型
   → 對策:監控 consumer lag,並對「lag 接近 retention」告警

② 進 DLQ(RabbitMQ 的 TTL → DLX)
   → ★ 比較好,但 DLQ 會被過期訊息灌滿,淹沒真正的失敗
   → 對策:DLQ 訊息帶 failure_kind=expired,分開計數(見 [[死信通道]])

③ ★ 業務層過期(自己判斷)
   → ★ 最好,因為你能記錄「丟了什麼、為什麼」

★★ consumer lag > retention 是最該告警的一個指標:
它代表「訊息正在被刪掉,而消費者還沒讀到」——資料正在遺失,而沒有任何錯誤。

★ 什麼時候不要設過期

  • ★ 事件通道:事件是歷史事實。OrderPlaced 過了三天仍然為真。
    → 設 TTL 等於「三天後這件事就不算發生過」,幾乎一定是錯的。
  • ★ 需要重放/回填的通道:TTL 就是你重放能力的上限。
  • 命令通常也不該過期,除非業務上真的有時效(限時優惠、即時報價)。

★ 兄弟辨析

差別
死信通道★ TTL 過期是進 DLQ 的原因之一(RabbitMQ)
訊息存放區需要長期保留時,把訊息落地
通道清除器★ 主動清掉整個通道,不是逐則過期
請求-回覆請求端的 deadline 是另一回事

🧪 我實際套用的紀錄

  • (待填)

⚠️ 注意 / 什麼時候不適用

  • 過期後的行為(丟棄或轉死信)依訊息系統而定。

  • 各節點時鐘不同步會影響過期判定。

  • 只適合有明確時效性的訊息;長期有效的資料不需設過期。

  • ★★ Kafka 的 retention.ms 不是訊息過期。retention 內的訊息都會被投遞,包含業務上已過期的——必須在消費端自己判斷。

  • ★★ RabbitMQ:整個佇列過期時訊息不會進 DLX,直接消失(2026-09-25 官方文件查證)。

  • ★ RabbitMQ 的 queue TTL 是惰性的:訊息在「到隊首時」才判定過期,中間的仍佔空間。

  • ★★ 業務性時限要放在訊息裡(ExpiresAt),不要用 broker TTL 表達——否則業務邏輯藏進基礎設施設定,不可測、不進版控。

  • ★★ consumer lag > retention 是最該告警的指標:資料正在遺失而沒有任何錯誤。

  • ★ 過期訊息被靜默丟棄時沒有任何指標。自己判斷過期時一定要加計數器。

  • ★ 事件通道不該設 TTL。事件是歷史事實,設 TTL 等於「過了三天就不算發生過」。

  • TTL 就是你重放能力的上限。需要回填就不要設短。

  • RabbitMQ 的 TTL 過期進 DLQ 會淹沒真正的失敗。要用 failure_kind 分開計數。

🔗 相關工具