iT邦幫忙

2025 iThome 鐵人賽

0
Software Development

微服務導入:從觀念到落地的架構實戰地圖系列 第 31

微服務導入 – Day 31 重構 – 分割單體式系統 III

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20251009/201782629t3aUaR3CY.png

在前面兩篇的文章說明「絞殺榕模式」與「抽象分支模式」都可以讓我們在正式環境中使用相同功能的新舊實作,並且可以在兩者間切換。但是,我們如何驗證抽取出來的功能是「正確的」?

平常,如果為一個既有系統進行重寫,在正式上線前會做什麼活動?我想可能很多人猜到了,就是「平行測試」。當我們將既有系統中的某個功能抽取出來、重寫為獨立的微服務時,雖然我們可能已經在開發與測試環境中進行了單元測試與整合測試,但這仍無法保證新服務在實際運行時的資料一致性與行為一致性。尤其是在高可靠性要求的系統中,一次錯誤就可能造成巨大的損失。

因此,在正式上線前,我們需要進行一段時間的平行測試

  • 新舊系統同時運行
  • 接收相同的請求
  • 回傳各自的處理結果
  • 由比對機制確認兩者行為的一致性

在我剛入行的年代,所謂的平行測試大多是人工操作:

  1. 操作人員在新舊系統分別輸入相同資料
  2. 執行相同業務流程
  3. 比對兩系統畫面與回傳資料
  4. 手動記錄差異並回報

這樣的方式雖然直觀,但效率極低,也容易出錯。若要維持營運效能,往往需要兩倍以上的人力投入,更別提維護資料一致性與日誌記錄的難度。

為了解決這個議題,我們希望「平行測試」這個作業可以更自動化一些,於是乎我們希望設計一個架構能協助我們進行「平行測試」的作業,與前兩天不同的是先前我們是找方法來切換新舊系統的呼叫,現在我們期望新舊系統可以收到相同的「請求」訊息。

平行測試自動化

為了解決效率與準確性的問題,我們傾向於設計自動化平行測試架構。其核心概念是:

設計一套中介機制,讓新舊系統同時收到相同的請求,主要回應仍由既有系統提供,但會額外記錄新系統的執行結果,並進行比對分析。

具體實作流程如下:

  1. 平行測試處理程式

在原本的 HTTP Proxy(如 Nginx、API Gateway)背後加入一個 平行測試處理模組(Parallel Test Handler),具備以下職責:

  • 將收到的請求轉發到兩套系統(舊系統 + 新微服務)
  • 從既有系統取得正式回應並回傳給用戶
  • 將新服務的回應記錄下來供後續比對
  1. 執行日誌與資料庫紀錄

每次請求除了觸發新舊系統處理外,還需將以下資訊記錄:

  • 請求內容(包含 headers / payload)
  • 既有系統的回應時間與內容
  • 新系統的回應時間與內容
  • 差異比對結果與分類
  1. 比對程式 (Result Comparator)
    https://ithelp.ithome.com.tw/upload/images/20251009/20178262mPF4itPGTv.png
    比對程式是整個平行測試的核心,其功能包括:
  • 深度比對新舊回應的 JSON 結構與欄位值
  • 可設定忽略欄位(如時間戳、UUID 等)
  • 結果分類(完全一致 / 欄位缺失 / 值不一致)
  • 日報 / 週報自動彙整並通知研發團隊

下游依賴問題

上述流程看似完整,但實際應用時還會遇到一個極大的挑戰:下游依賴(Downstream Dependencies)

舉例來說,如果你所抽取出來的功能還需要呼叫其他內部服務(例如:發送通知、更新帳戶餘額、查詢客戶狀態),那麼在平行測試時就可能產生兩次呼叫,導致:

  • 狀態異常(例如:通知寄出兩封)
  • 數據錯誤(例如:餘額被扣兩次)
  • 外部依賴負荷過重(例如:第三方 API 接收兩倍請求)

因此,針對這類依賴模組,我們需要進一步設計:「抽象分支模式(Branch by Abstraction)」。

抽象分之實作

在依賴服務之上建立一層抽象,例如 NotificationService 介面,在平行測試階段注入兩種實作:

  • 真實實作(提供舊系統使用)
  • 模擬實作(新系統使用,只記錄請求不執行副作用)

這樣就可以避免副作用,同時仍能記錄下新系統是否正確觸發該依賴邏輯,並納入比對項目中。

https://ithelp.ithome.com.tw/upload/images/20251009/20178262tsbjE0BAP7.png

建議架構設計

一個完整的自動化平行測試架構,應包含下列元件:

  • Reverse Proxy + Router(請求路由)
  • 平行測試處理器(轉發請求 / 收集回應)
  • 結果記錄系統(Request + Response log)
  • 資料比對模組(Result Comparator)
  • 差異報表系統(每日彙整 / 通知機制)
  • 抽象依賴模組(防止副作用)

可搭配下列技術:

  • Kafka / RabbitMQ 作為非同步訊息傳遞通道
  • MongoDB / ElasticSearch 儲存請求記錄與比對結果
  • Prometheus + Grafana 監控新舊系統效能差異
  • GitLab CI / Jenkins 排程自動 replay 測試

平行測試的適用時機

由於建置與維護平行測試的成本極高,因此建議應用在以下情境:

  • 高風險業務邏輯(如金流、交易、合約簽署)
  • 對結果一致性要求極高的功能(如報稅、對帳)
  • 有複雜轉換邏輯的資料處理模組
  • 非同步遷移計劃中的早期驗證階段

反之,如果是低風險、無副作用的查詢型功能(如使用者個人頁面資料),可考慮以 Shadow Traffic 或 A/B 測試替代。

精力應該花在刀口上,才能製造出槓桿


結語

平行測試的設計與實作是一門深奧的工程藝術,它既是一種保險措施,也是一種架構成熟度的體現。它可以讓我們在正式導入新架構前,用數據與結果證明「我們做對了」。但同時也必須正視它的投入成本與維運複雜度,並根據實際業務特性做出平衡取捨。

或許,在某些小型系統遷移中,「讓使用者手動敲兩次」反而是最省力又有效的平行測試方法。但在大型、關鍵的系統轉換中,唯有投入更多的設計與自動化機制,才能讓我們的微服務轉型真正站穩腳步。


上一篇
微服務導入 – Day 30 鐵人賽的最後一天
系列文
微服務導入:從觀念到落地的架構實戰地圖31
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言