🎯 什麼情境該想到我
當你「想主動、定期地確認訊息處理元件仍運作正常,而不是等真的出錯才發現」的時候。
⚙️ 怎麼用(步驟 / 公式)
意圖:定期注入內容已知的測試訊息,並在輸出端驗證結果是否符合預期,藉此主動監測元件是否正常運作。
做法 / 結構要點:
- 由測試資料產生器發出可辨識的測試訊息,注入待測元件。
- 讓測試訊息與正式訊息一起流經處理。
- 在輸出端用測試訊息分離器把測試訊息挑出,驗證器比對結果,異常則告警。
★★ 它要抓的是「其他監控抓不到」的那一類故障
★ 傳統監控看得到的:
✅ 行程掛了(liveness) ✅ CPU/記憶體異常
✅ 佇列積壓(lag) ✅ 錯誤率上升
★★ 傳統監控看不到的 —— 這才是測試訊息的目標:
★ 服務活著、沒有錯誤,但「靜默地產生錯誤的結果」
★ 服務活著、沒有積壓,但「根本沒有訊息進來」(★ 上游停了)
★ 整條管線的某一段悄悄不轉了(配接器掛了,見 [[通道配接器]])
★★ 最重要的一個場景:「沒有訊息」這件事不會觸發任何告警。
上游停止發送 → lag = 0、錯誤率 = 0、CPU 正常 → 所有儀表板都是綠的。
★ 測試訊息(合成監控)是唯一能抓到這件事的手段。
⚠️ 另一個更便宜的做法:對「最後一筆真實訊息的時間」告警——
流量穩定的通道用這個就夠了,不必注入測試訊息。
★★ 設計的四個必要決定
① ★★ 測試訊息怎麼被識別(★ 最重要)
✅ 信封裡一個明確的欄位:is_synthetic: true
❌ 靠特殊的 ID 格式("TEST-001")—— ★ 太容易被誤判或誤用
② ★★ 誰負責把它濾掉
→ 每個消費者都要記得濾 = ★ 一定有人忘記 ⇒ ★★ 測試訊息造成真實的副作用
→ ✅ ★ 做進共用的消費端閘道(見 [[訊息閘道]]),預設就濾掉
③ ★ 它走不走真實路徑
走真實路徑 → ★ 測得更真,但★★ 有副作用風險
走影子路徑 → 安全,但★ 測不到真實路徑的問題
→ ★ 折衷:走真實路徑,但在「最後一步(產生副作用之前)」被攔下
④ ★ 誰驗證它到了
→ ★ 一個獨立的驗證器訂閱終點通道,比對「發出的」與「收到的」
→ ★★ 沒有驗證器的測試訊息 = 沒有意義(你發了但沒人確認它到了)
★★ Go 的實作:濾掉測試訊息必須是「預設行為」
// ★★ 在共用閘道裡濾掉,而不是每個 handler 自己判斷
func (a *Activator) Handle(ctx context.Context, msg Message) error {
e, err := decode(msg)
if err != nil { return err }
if e.IsSynthetic {
if !a.acceptsSynthetic { // ★★ 預設 false —— 選擇加入,不是選擇退出
metrics.SyntheticSkipped.Inc()
return msg.Ack() // ★ ack 掉,讓它不堵住
}
ctx = withSyntheticFlag(ctx) // ★ 讓下游知道「不要真的發錢」
}
return a.handler.Handle(ctx, e)
}★★ 「預設不接受、明確選擇加入」是唯一安全的設計:
反過來(預設處理、要自己濾掉)→ 只要有一個服務忘記濾,測試訊息就造成真實副作用
(真的寄信、真的扣款)。
★ 這正是「安全的預設值」原則:讓「忘記做某件事」的後果是保守的,不是危險的。
★★ 最危險的失敗模式:測試訊息造成真實副作用
★ 真實發生過的樣貌:
① 測試訂單流進真實的出貨系統 ⇒ ★ 真的出貨了
② 測試付款訊息進真實的金流 ⇒ ★★ 真的扣款
③ 測試訊息進了報表 ⇒ ★ 營收數字錯了(而且很難發現)
④ ★ 測試訊息進 DLQ ⇒ 淹沒真正的失敗
★ 四個防護,缺一不可:
① 預設不接受(見上);② 產生副作用的最後一步再攔一次;
③ ★ 測試訊息一律用明顯的測試資料(TEST_ 前綴的 ID、0 元金額);
④ ★ 報表與指標明確排除 is_synthetic。
★ 什麼時候不需要測試訊息
- ★ 流量穩定的通道 → 對「最後一筆真實訊息的時間」告警就夠了,更便宜也更安全。
- ★ 已經有端到端的合成監控(從 API 打進去、驗證最終結果)→ 那是更完整的版本。
- ★ 有副作用且無法安全攔下的流程(實體出貨、金流)→ 風險大於收益,改用被動監控。
★ 兄弟辨析
| 差別 | |
|---|---|
| 控制匯流排 | ★ 測試訊息常透過它注入與收集結果 |
| 竊聽器 | 觀察真實訊息,不注入 |
| 繞道 | ★ 導流真實訊息;測試訊息是注入新的 |
| 工具-注入故障與韌性演練 | ★ 更主動的版本:不只探測,還製造故障 |
🧪 我實際套用的紀錄
- (待填)
⚠️ 注意 / 什麼時候不適用
-
要能把測試訊息與正式訊息區分,避免污染正式資料或下游。
-
測試涵蓋的路徑要有代表性。
-
常由控制匯流排協調注入與收集結果。
-
★★ 最重要的目標是「沒有訊息」這種故障——lag=0、錯誤率=0、儀表板全綠,但上游停了。
-
★★ 但更便宜的做法常常是「對最後一筆真實訊息的時間告警」。流量穩定的通道用這個就夠,不必注入。
-
★★ 濾掉測試訊息必須是預設行為(預設不接受、明確選擇加入)。 反過來只要有一個服務忘記濾就造成真實副作用。
-
★★ 測試訊息造成真實扣款/出貨是真實發生過的事故。 要四層防護:預設不接受、副作用前再攔、明顯的測試資料、報表排除。
-
★ 靠 ID 格式(
TEST-001)識別太脆弱。用信封裡明確的is_synthetic欄位。 -
★★ 沒有驗證器的測試訊息沒有意義——你發了但沒人確認它到了。
-
★ 測試訊息進 DLQ 會淹沒真正的失敗。要在 DLQ 指標裡分開計數。
-
有副作用且無法安全攔下的流程(實體出貨、金流)不要用這個模式,風險大於收益。
🔗 相關工具
- 控制匯流排 Control Bus(同家族,協調測試注入與收集)
- 智慧代理 Smart Proxy(同家族,被動量測與此主動驗證互補)
- 企業整合模式
- 控制匯流排 —— 注入與收集結果的通道
- 竊聽器 —— 觀察真實訊息
- 繞道 —— 導流真實訊息 vs 注入新訊息
- 死信通道 —— 測試訊息不該淹沒真正的失敗
- 訊息 —— 信封裡的 is_synthetic 欄位
- 工具-注入故障與韌性演練 —— 更主動的版本