🎯 什麼情境該想到我
當你「要透過訊息通道傳送一份資料」的時候:把資料封裝成一個可被訊息系統傳輸的單位。
⚙️ 怎麼用(步驟 / 公式)
意圖:把要傳輸的資料包成訊息——訊息系統能傳送的最小資料單位。
做法 / 結構要點:
- 一則訊息通常分兩部分:標頭(header) 給訊息系統用(如識別碼、回覆位址、型別、過期時間),內容(body) 是實際承載的資料。
- 訊息可扮演不同角色:命令(要對方做事)、文件(傳遞資料)、事件(通知發生了什麼)。
- 發送方把資料寫入訊息,訊息系統負責在通道上傳遞它。
★ 一則訊息的三層結構(每一層的責任不同)
┌─ 通道/broker 的 metadata ── offset、partition、timestamp、delivery count(★ 你不擁有)
├─ 標頭 headers ───────────── ★ 路由與運維用:message-id、correlation-id、
│ content-type、trace-parent、schema-version
└─ 內容 body ──────────────── ★ 業務資料。路由不應該需要解開它
★★ 最重要的一條原則:路由與運維資訊放標頭,業務資料放內容。
路由器需要解開 body 才能決定去向 → 路由器就得認識每一種 schema,
schema 一改就要改路由器(見 訊息路由器、信封包裝器)。
★ Go 的訊息型別設計
// ★ 用信封包裝,讓 body 保持不透明
type Envelope struct {
MessageID string `json:"message_id"` // ★ 冪等去重用([[冪等接收者]])
CorrelationID string `json:"correlation_id"` // ★ 串起一次業務流程([[關聯識別碼]])
Type string `json:"type"` // ★ "orders.order.placed"
SchemaVersion int `json:"schema_version"` // ★ 讓消費者能判斷自己認不認得
OccurredAt time.Time `json:"occurred_at"` // ★ 事件發生時間 ≠ 訊息送出時間
Data json.RawMessage `json:"data"` // ★ 延遲解析:路由不必認識內容
}★ OccurredAt 與「broker 的 timestamp」要分清楚:
重送、重放、積壓都會讓兩者差很遠。業務邏輯一律用 OccurredAt。
★★ 訊息大小:這是最容易踩的硬限制
實測/查證 2026-09-25:
| broker | 上限 |
|---|---|
| SQS | ★ 1,048,576 bytes(1 MiB)——注意:不再是舊資料常說的 256 KB。要更大要用 Extended Client(把 body 放 S3) |
| Kafka | 由 message.max.bytes/max.message.bytes 決定,預設約 1 MB 量級;★ 改大會連帶影響 broker 記憶體與複製延遲 |
| RabbitMQ | 可設定,但大訊息會嚴重拖慢佇列 |
★ 超過限制的正確做法不是調高上限,是 寄物單:
把大 payload 放物件儲存,訊息裡只放 key。
// ❌ 把 5 MB 的 PDF 塞進訊息
// ✅ 寄物單
type DocReady struct {
DocID string `json:"doc_id"`
S3Key string `json:"s3_key"` // ★ 訊息只帶位址
SHA256 string `json:"sha256"` // ★ 讓消費者能驗證拿到的是同一份
}★ 訊息的三種語義(混用是事件驅動架構的頭號設計錯誤)
| 命令訊息 | 事件訊息 | 文件訊息 | |
|---|---|---|---|
| 意思 | 「請做這件事」 | 「這件事已發生」 | 「這是資料」 |
| 接收者數 | ★ 恰好一個 | ★ 零到多個 | 任意 |
| 命名 | 祈使句 CreateOrder | ★ 過去式 OrderPlaced | 名詞 |
| 可以拒絕 | ✅ | ❌ 已經發生了 | — |
★ schema 演進:訊息的 schema 是跨行程契約
★ 一定要能容忍「消費者是舊版」:
① 只新增「可選」欄位,不改既有欄位的意義
② 不重用 protobuf 的欄號、不改型別
③ 不相容的變更 → 開一條新版本通道(v2),兩條並行直到舊消費者下線
→ 完整規則見 工具-資料編碼與演進。
🧪 我實際套用的紀錄
- (待填)
⚠️ 注意 / 什麼時候不適用
-
訊息通常有大小限制,超大資料需改用參照(如只傳位址/ID)而非整包塞進去。
-
標頭與內容的格式需雙方(或透過轉換器)達成共識,否則接收端無法解讀。
-
★★ 路由資訊放標頭、業務資料放內容。路由器要解開 body 才能決定去向,就會被 schema 綁死。
-
★★ SQS 的上限是 1 MiB(2026-09-25 查證),不是舊資料常說的 256 KB。 版本敏感的數字要查證。
-
★ 超過大小限制要用 寄物單,不要調高 broker 上限——調大會影響記憶體與複製延遲。
-
★ 訊息一定要有 message-id(冪等)與 correlation-id(追因果)。 事後補很痛。
-
★ 事件發生時間 ≠ 訊息送出時間 ≠ broker timestamp。業務邏輯用前者。
-
★ 命令/事件/文件的語義不可混用。把命令發成事件 → 兩個服務都處理 → 寄兩封信。
-
schema 是跨行程契約。消費者可能是舊版,只能做向後相容的變更。
-
不要在訊息裡放敏感資料。broker 有 retention、有備份、有日誌——那些地方都會留下來。
🔗 相關工具
- 訊息通道 Message Channel(訊息流經的管道)
- 訊息端點 Message Endpoint(應用讀寫訊息的接口)
- 訊息轉換器 Message Translator(在系統間轉換訊息的格式與結構)
- 企業整合模式
- 命令訊息、事件訊息、文件訊息 —— 三種語義
- 信封包裝器 —— 標頭與內容分層
- 寄物單 —— 大 payload 的處理
- 關聯識別碼 —— correlation id
- 冪等接收者 —— message id 的用途
- 格式指示器 —— schema 版本怎麼標
- 工具-資料編碼與演進 —— schema 相容性規則