🎯 什麼情境該想到我
當你「訊息內容太龐大(大檔、大量資料),不想讓它整包在系統裡流動,只想帶一張憑證、需要時再取回」的時候。
⚙️ 怎麼用(步驟 / 公式)
意圖:把訊息的大量內容存到持久儲存,訊息只攜帶一張「取件單」(鍵 / ID),需要時再憑單取回完整內容,減少傳輸量。
做法 / 結構要點:
- 收到訊息時,把大內容存進資料庫或儲存區,換得一個唯一鍵。
- 移除訊息本體、只留這個鍵(取件單)往下送。
- 下游需要完整內容時,用取件單去儲存區取回。
★ 什麼時候需要它:三個明確的訊號
① ★ 訊息超過 broker 上限(查證 2026-09-25)
SQS:1,048,576 bytes(1 MiB)
Kafka:由 message.max.bytes 決定,預設約 1 MB 量級
→ ★ 調高上限不是答案:會連帶影響 broker 記憶體、複製延遲、GC
② ★ 大多數消費者不需要完整內容(只有一個需要)
→ 為了那一個而讓所有人都收 5 MB,是純浪費
③ ★★ 訊息含敏感資料,不想讓它留在 broker 的 retention/備份/DLQ 裡
→ ★ 這是安全用途,常被忽略(見 [[內容過濾器]])
★ Go 的實作與四個必帶欄位
type DocReady struct {
DocID string `json:"doc_id"`
StoreKey string `json:"store_key"` // ★ 物件儲存的 key
SizeBytes int64 `json:"size_bytes"` // ★ 讓消費者能預先決定要不要處理
SHA256 string `json:"sha256"` // ★★ 驗證拿到的是同一份
ExpiresAt time.Time `json:"expires_at"` // ★★ 寄物櫃什麼時候會清掉
}★★ SHA256 與 ExpiresAt 是最常被省略、也最重要的兩個:
- 沒有
SHA256→ 物件被覆寫時你不會知道(同一個 key,不同內容)。 - 沒有
ExpiresAt→ 消費者不知道「還來不來得及」,也沒人知道什麼時候該清。
★★ 這個模式的核心難題:寄物櫃與訊息的生命週期不一致
★ 四種會出事的組合:
① ★★ 物件先被刪,訊息還在
S3 lifecycle 設 7 天,訊息在 DLQ 躺了 10 天 → ★ 重放時拿不到內容
→ ★ 規則:寄物櫃的保留期必須「長於」訊息的最長生命週期
(含 DLQ retention + 人工處理時間)
② ★★ 訊息丟了,物件留著 → 孤兒物件,永遠沒人清
→ ★ 靠 lifecycle policy 自動過期,不要靠應用程式刪
③ ★★ 寫入順序反了
❌ 先發訊息、後寫物件 → 消費者可能先到,讀到 404
✅ ★ 先寫物件(並確認成功)、再發訊息
④ ★ 誰負責刪
消費者刪 → ★ 多個消費者時,第一個刪完其他人就讀不到了
→ ★★ 一律用 lifecycle policy 自動過期,不要讓消費者刪
★★ ③ 和 ④ 是最常犯的兩個錯。
③ 讓消費者間歇性讀到 404(而且在高速通道上機率不低);
④ 在有多個訂閱者的發布訂閱通道上直接造成資料遺失。
★ 存取控制
// ★ 兩種給法
// ① 直接給 key,消費者用自己的 IAM 權限讀
// → ★ 需要所有消費者都有那個 bucket 的權限(★ 權限面變寬)
// ② ★ 給預簽名 URL(presigned URL)
// → ★ 精確到單一物件、有有效期;消費者不需要 bucket 權限
// → ⚠️ 但有效期通常短(幾小時),★ 訊息在 DLQ 躺三天後 URL 就失效了★ 務實做法:訊息帶 key(不帶 presigned URL),消費者用 IAM 讀。
presigned URL 的有效期和訊息生命週期幾乎必然不匹配。
★ 什麼時候不要用
- ★ 內容很小(幾 KB)——多一次網路往返不划算。
- ★ 消費者「一定」需要完整內容且處理極快——直接放訊息裡更簡單、更可靠。
- ★ 沒有可靠的共用儲存。寄物櫃變成新的單點,而且它的可用性現在決定訊息流的可用性。
- ★ 需要 broker 的原生重放。訊息還在但物件被清掉的重放,等於不能重放。
★ 兄弟辨析
🧪 我實際套用的紀錄
- (待填)
⚠️ 注意 / 什麼時候不適用
-
需要額外的儲存與清理機制(何時刪除存放的內容)。
-
取回是額外一趟查詢,用延遲換取傳輸量的節省。
-
儲存區成為相依點,要考慮其可用性。
-
★★ 順序必須是「先寫物件、確認成功、再發訊息」。 反了會讓消費者讀到 404。
-
★★ 一律用 lifecycle policy 自動過期,不要讓消費者刪物件。 多訂閱者時第一個刪完其他人就讀不到。
-
★★ 寄物櫃保留期必須長於訊息的最長生命週期,含 DLQ retention 與人工處理時間。否則重放時拿不到內容。
-
★ 一定要帶
SHA256(驗證是同一份)與ExpiresAt(消費者知道來不來得及)。 -
★ 不要用 presigned URL:有效期通常幾小時,和訊息生命週期(含 DLQ 幾天)不匹配。帶 key 讓消費者用 IAM 讀。
-
★ 寄物櫃是新的單點。它的可用性現在決定訊息流的可用性。
-
★ 調高 broker 的訊息上限不是答案,會影響記憶體、複製延遲與 GC。
-
內容很小就不要用,多一次網路往返不划算。
🔗 相關工具
- 內容過濾器 Content Filter(同家族,也是縮減訊息內容)
- 內容擴充器 Content Enricher(同家族,取回內容概念與其補資料互補)
- 訊息存放區 Message Store(存放大內容的持久儲存機制)
- 企業整合模式
- 內容擴充器 —— 反向:由消費者去查
- 內容過濾器 —— 移除 vs 搬走
- 訊息存放區 —— 為查詢而保存
- 檔案傳輸 —— 大量資料的另一條路
- 訊息 —— broker 的大小上限
- 死信通道 —— DLQ retention 決定寄物櫃的保留期下限