團隊初期使用 HTTP 傳輸 WCF 服務,服務處理過程中寫入資料庫。壓力測試一週發現訊息遺失,主要為包含訂單資訊的訊息,且集中在 10 分鐘內。日誌分析發現:關鍵 Windows 修補程式自動安裝導致伺服器重啟。HTTP 處理訊息時開啟資料庫交易,寫入資料提交。伺服器重啟導致交易中斷,資料庫回滾保持一致,但原始訊息資料既不在記憶體也不在網路堆疊中——訊息遺失。對訂單系統意味著經濟損失;空管系統則可能釀成災難。
決定從 HTTP 轉用穩定傳輸,在 MSMQ 與 SQL Service Broker 間選擇。Service Broker 優勢:訊息傳遞在資料庫內,避免分散式交易;MSMQ 優勢:Windows 內建零開銷、與 WCF 緊密整合、伺服器間點對點通訊不加重資料庫負載。最終決定每台伺服器使用專用 MSMQ 隊列。
Message.Recoverable = true 或用 NetMsmqBinding (預設 Durable = true)。NetMsmqBinding 時,非穩定傳遞訊息需獨立端點,設定非交易隊列與 Durable = false。OperationBehaviorAttribute.TransactionScopeRequired 搭配佇列傳輸輕鬆實現,出隊交易用於處理訊息。處理訊息後,服務回覆/發送其他訊息。若用 HTTP/TCP 等不識別交易的技術極危險。資料庫死鎖導致交易回滾,已發送的其他系統資訊可能不實。圖 1 展示死鎖導致系統 A 收到錯誤通知,引發全域衝突。
訂單處理實例:採購訂單到達 → 更新狀態 → 通知倉儲 → 更新 CRM 客戶值 → CRM 死鎖 → 交易回滾 → 重試時客戶資料顯示無交易 → 倉儲系統未收到回滾通知 → 產品在裝卸台等待超過一小時 → 單一事故導致週利潤降低 30%。轉用 MSMQ 可迎刃而解。
MSMQ 發送訊息:方法返回不代表訊息已發送。訊息先本地存於外發隊列。在交易內發送時,僅提交交易後 MSMQ 才真正發送。死鎖或交易中止時,外發隊列訊息被刪除。注意:交易性訊息傳遞不意味著發送者與處理服務共享交易。訊息到達處理服務僅表示發送者成功提交交易,不代表接收服務處理行為。
位元組到達端點時反序列化可能失敗:XML 宣告的資料型別未部署/版本錯誤、舊客戶端對新服務端點發送不相容訊息。訊息可能含重要資料,不宜丟棄或阻塞輸入隊列。解決方案:直接移至錯誤隊列(無需等待 n 次回滾,因處理結果必定失敗)。
穩定訊息傳遞非萬靈丹,有相關開銷。企業對企業案例:訂單系統與外部物流公司通訊。平均訊息 1MB,每秒 10 筆訂單。物流伺服器不可用時,訊息堆積外發隊列:I/O 10MB/s (600MB/min)。3 小時後發現,系統嘗試向 36GB RAID 5 寫入 100GB 資料,伺服器失去穩定性且難以備份。備份過程中遺失數百萬美元訂單。
Message.TimeToBeReceived 設定。