🎯 什麼情境該想到我
當你「訊息有時效,過了期限就不該再被處理」的時候。
⚙️ 怎麼用(步驟 / 公式)
意圖:標示訊息在多久後失效,避免接收端處理到過時、無意義的資料。
做法要點:
- 在訊息標頭設定過期時間(有效期限)。
- 若訊息在期限內仍未被消費,訊息系統將其作廢。
- 作廢的訊息通常轉送到 Dead Letter Channel(死信通道),而非交付給接收者。
★ 各家 broker 的 TTL 機制(粒度差很多)
查證 2026-09-25。
| broker | 機制 | ★ 粒度 |
|---|---|---|
| RabbitMQ | x-message-ttl(queue 級)、expiration(每則訊息) | ★ 兩種都有;過期會進 DLX(見下) |
| SQS | 訊息 retention | ★ 只有 queue 級:預設 4 天,最短 60 秒,最長 14 天 |
| Kafka | retention.ms(topic 級) | ★★ 沒有 per-message TTL;而且它是「保留期」不是「過期」 |
| NATS JetStream | stream 的 max_age | stream 級 |
★★ 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分開計數。
🔗 相關工具
- 事件訊息 Event Message(時效性強的通知常需設過期)
- 請求-回覆 Request-Reply(回覆等太久即過時,可用過期作廢)
- 企業整合模式
- 死信通道 —— TTL 過期的去處之一
- 訊息存放區 —— 需要長期保留
- 通道清除器 —— 主動清空整個通道
- 請求-回覆 —— 請求端的 deadline
- 保證投遞 —— 過期與保證是對立的
- 事件訊息 —— 為什麼事件不該過期