🎯 什麼情境該想到我
當你「通道裡殘留了過期或不該處理的舊訊息(例如測試 / 重啟後),想把它們清掉以免干擾」的時候。
⚙️ 怎麼用(步驟 / 公式)
意圖:移除通道中殘留或不再需要的訊息,避免舊訊息在測試、重啟或重跑時造成非預期行為。
做法 / 結構要點:
- 用一個清除器連上目標通道,把其中的訊息取出並丟棄。
- 可全清,或依條件(如過期、特定屬性)選擇性清除。
- 常在測試前 / 系統重啟後執行,確保通道乾淨。
★★ 這是一個「破壞性操作」,設計時要當成危險工具
★ 它的正當用途幾乎只有三種:
① ★★ 測試/開發環境的重置(★ 最主要、也最安全的用途)
② ★ 生產事故:通道裡全是毒訊息,重新部署也救不了,必須清空才能前進
③ ★ 已知過期且無意義的積壓(限時活動結束後累積的通知)
★★ 除此之外,「清空通道」等於「刻意丟棄資料」。
而在事故當下做這件事,是最容易造成不可逆損失的操作之一。
★★ 各家 broker 的清除方式與可逆性
查證 2026-09-25。
| broker | 方式 | ★ 可逆嗎 |
|---|---|---|
| RabbitMQ | rabbitmqctl purge_queue / 管理介面 | ★★ 不可逆 |
| SQS | PurgeQueue API | ★★ 不可逆;且 60 秒內只能呼叫一次 |
| Kafka | ★ 不清訊息,而是「移動 consumer offset」 | ★★ 可逆!(offset 可以移回去,只要還在 retention 內) |
| Kafka(真的刪) | kafka-delete-records 或縮短 retention | 不可逆 |
★★ Kafka 的「跳過積壓」是可逆的,這是它最被低估的優勢:
# ★ 把 consumer group 的 offset 移到最新 —— 訊息還在 log 裡
kafka-consumer-groups --reset-offsets --to-latest --group g1 --topic t1 --execute
# ★★ 發現不該跳 → 移回去就好(只要還在 retention 內)
kafka-consumer-groups --reset-offsets --to-datetime 2026-09-25T10:00:00.000 --group g1 --topic t1 --execute★ 所以在 Kafka 上,「清除通道」應該一律用「移 offset」而不是刪訊息。
★★ 清除前必做的三件事
① ★★ 先備份:把要清掉的訊息落地
→ ★ RabbitMQ/SQS 上:先用一個消費者把它們讀進 [[訊息存放區]]
→ ★★ 沒有備份的 purge 是不可逆的資料遺失
② ★ 先暫停生產者(或至少知道還在進多少)
→ ★ 否則你清完的下一秒又滿了(見 [[控制匯流排]] 的暫停能力)
③ ★ 記錄:誰、什麼時候、清了哪個通道、清了幾則、為什麼(ticket)
→ ★★ 事後一定會有人問「那些訊息去哪了」
★★ 權限與防護:這個操作必須難以誤觸
★ 四層防護:
① ★★ 生產環境的 purge 權限不該給一般開發者的日常帳號
② ★ 一定要有「環境確認」步驟(★ 打錯環境是最常見的事故)
③ ★ 不要把 purge 做成一個 HTTP GET 端點(★ 會被瀏覽器預取、被爬蟲觸發)
④ ★★ 要有審計日誌
// ★ 如果真的要提供這個端點
mux.HandleFunc("/admin/purge", requireAuth(requireConfirm(func(w, r) {
if r.Method != http.MethodPost { http.Error(w, "", 405); return } // ★ 不能是 GET
if r.FormValue("env") != cfg.Env { http.Error(w, "環境不符", 400); return }
if r.FormValue("channel") != r.FormValue("confirm_channel") { // ★ 打兩次名字
http.Error(w, "確認不符", 400); return
}
audit.Log(r, "purge", …) // ★ 先記錄再執行
…
})))★★ 更好的替代方案(按推薦度)
① ★★ Kafka:移 offset(可逆)
② ★★ 把訊息「搬到別處」而不是刪掉
→ 一個消費者把它們全部轉發到 archive.<channel> 通道
→ ★ 通道空了,而訊息還在 ⇒ 可以事後分析、可以選擇性重放
③ ★ 設定 TTL 讓它自然過期(見 [[訊息過期]])
→ ⚠️ 但注意 RabbitMQ 的陷阱:整個佇列過期時訊息不進 DLX
④ ★ 修好問題然後讓它正常消化
→ ★★ 多數「必須清空」的情況其實是「消費者壞了」——修消費者比清訊息正確
★★ ② 是最好的通用做法:它達成了「清空」的效果,但保留了回頭路。
★ 兄弟辨析
🧪 我實際套用的紀錄
- (待填)
⚠️ 注意 / 什麼時候不適用
-
清除是破壞性動作,誤清會丟掉有效訊息,務必謹慎。
-
生產環境要嚴格控管權限與時機。
-
多用於測試、除錯、維運情境。
-
★★ 清空通道是刻意丟棄資料,而且 RabbitMQ/SQS 上不可逆。 事故當下做這件事最容易造成不可逆損失。
-
★★ Kafka 上一律用「移 offset」而非刪訊息——它是可逆的(只要還在 retention 內)。
-
★★ 清除前先備份(用消費者把訊息讀進 訊息存放區)。沒有備份的 purge 就是資料遺失。
-
★★ 更好的做法是「搬到 archive 通道」而不是刪掉:達成清空效果但保留回頭路。
-
★ 清除前先暫停生產者,否則清完下一秒又滿了。
-
★★ purge 端點不能是 GET(會被瀏覽器預取、爬蟲觸發),要有環境確認與二次確認,並記審計日誌。
-
★ 生產環境的 purge 權限不該在一般開發者的日常帳號上。 打錯環境是最常見的事故。
-
★★ 多數「必須清空」的情況其實是「消費者壞了」 —— 修消費者比清訊息正確。
-
毒訊息應該進 DLQ,如果它逼得你清空整條通道,代表 DLQ 機制沒做好。
🔗 相關工具
- 測試訊息 Test Message(同家族,測試前常先清通道)
- 控制匯流排 Control Bus(同家族,可透過它觸發清除)
- 企業整合模式
- 控制匯流排 —— 清除指令的通道
- 訊息過期 —— 被動的逐則過期
- 死信通道 —— ★ 毒訊息該進 DLQ,不該逼你清空通道
- 訊息存放區 —— 清除前的備份去處
- 保證投遞 —— 清除是它的反面