解決方案
SoundCloud 的後端由微服務組成,介面是手工打造的 REST/JSON,雖然容易除錯,但每個端點的慣例——HTTP 方法、JSON 欄位名稱、時間戳格式、錯誤結構——都取決於建置該端點的團隊。內部指引能幫的有限:曾有客戶端送出 camelCase 欄位給期待 snake_case 的伺服器,導致一次服務中斷;而要理解任何端點,都得閱讀應用程式碼,而非依賴契約。
SoundCloud 打造了 Twinagle,這是 Twitch 的 Twirp RPC 協定在 Scala/Finagle 上的實作,讓工程師能以 protobuf 定義一次 API,並據此產生伺服器與客戶端程式碼。他們先遷移流量最高的曲目授權服務。他們沒有直接切換,而是讓 REST 與 Twirp 在依百分比控制的旗標後並行運作:在低 rollout 百分比時,兩個端點都會被呼叫並互相比對,但只回傳 REST 的回應,因此不一致會以記錄下來的差異浮現,而不是變成使用者可見的錯誤。
達成什麼
將流量鏡像到新端點、進行差異比對,然後才切換
為何有效
從單一 protobuf 契約產生伺服器與客戶端程式碼,消除了團隊各自發明 JSON 欄位命名與 HTTP 慣例所造成的那一類錯誤。
在切換前先以少量流量百分比並行執行兩個端點,讓團隊能在沒有任何使用者看到錯誤答案的情況下捕捉到回應不一致。
從單一客戶端、高流量的服務著手,讓第一次遷移的整合面保持狹小,同時仍能在真實負載下驗證 Twinagle。
保持既有業務邏輯不變,並將新程式碼限制在薄薄一層序列化層,限縮了新錯誤可能藏身之處。
可套用之處
在汰除一個仍在運作的系統之前,讓替代系統並行回應每一個請求,並與現行系統進行差異比對——錯誤會在舊系統仍負責回應時浮現。
後續發展
影子比對式的 rollout 在使用者受到影響前捕捉到數個關鍵錯誤,SoundCloud 將曲目授權服務逐步提升到 100% Twirp 流量,第一次嘗試就沒有服務中斷,也沒有錯誤。兩個服務之間的頻寬因從 JSON 改用二進位 protobuf 而下降超過 40%,團隊也刪除了該服務所有自訂的 JSON 序列化程式碼。SoundCloud 接著將其他服務轉換到 Twinagle,並讓它成為所有新服務的預設方案。
追溯依據
參考來源
- Announcing Twinagle: Twirp and Protobuf for Finagle SoundCloud Engineering · developers.soundcloud.com ·