如何保證業務變更的可回滾性
背景
采用快速迭代的開發方式的互聯網公司常常一天之內要對線上業務做多次變更,如果在變更業務後出現了傷害用戶體驗或影響收入的意外情況,最簡單快速的解決方法就是將線上業務回滾到變更前的狀態。保證業務變更的可回滾性,對於控製風險和保障開發人員的安全感,都有重要的意義。本文介紹了幾種保證業務變更可回滾的方法。
將代碼和配置整體打包
如果將代碼和配置分開部署,在回滾的時候就會遇到"應該是先回滾代碼還是回滾配置"的難題,所以,要想輕鬆回滾,在部署的時候,一定要將代碼和配置整體打包。在具體的實踐方式上,我強烈建議采用容器化部署,在CI係統中將變更後的代碼和配置build為一個docker image, 並給不同版本的容器打上不同的tag, 通過切換tag便能實現整體服務的快速回滾。
引入中間版本
對於單體應用,采用容器化的手段將代碼和配置整體打包部署就能很好的保證可回滾性,但是,這僅是一個過度簡化的模型,實際的線上係統則要複雜許多,一般都是由有依賴關係的多個子服務構成。例如,前端web係統會訪問後端數據服務,後端數據服務會訪問數據庫,或者給批量作業係統下發任務。對於這種有依賴關係的變更,怎樣開發和部署才能如何保證可回滾性?
首先,係統設計要保證調用的單向性,即如果服務A調用了服務B,那麼服務B一定不會調用服務A。在滿足單向調用的前提下,可以使用下列方法來保證可回滾性。
例如,有兩個子服務A和B,服務A會調用服務B,業務需求需要同時將A變更為A'和將B變更為B'才能實現。
初始狀態: A -> B
最終狀態: A' -> B'
但是,由於A'和B以及A和B'的實現不兼容,所以不能出現A -> B'或A' -> B的中間狀態。
解決辦法:
- 將B變更為B'',B''可以同時兼容A和A',即A -> B''與A' -> B''均成立, 此時係統狀態變為A -> B'',如果發現問題,可回滾成狀態A -> B
- 將A變更為A', 此時係統狀態變為A' -> B'',如果發現問題,可回滾成狀態A -> B''
- 將B''變更為B', 此時係統狀態變為A' -> B', 順利抵達最終狀態,並且切換過程平滑, 如果發現問題,可回滾成狀態A' -> B''
綜上可見,通過引入中間版本B'',就能保證對存在依賴關係的兩個子服務的變更的可回滾性。
舉個具體的例子,當前的用戶登錄係統隻要求輸入用戶名和密碼,由前端係統將用戶名和密碼發送給後端係統進行驗證,現在,需要在用戶登錄時輸入驗證碼。顯然,這一改進需要前後端係統一起配合才能實現:
- 前端係統的界麵要加入驗證碼的圖片顯示和輸入框,並且調用驗證接口時需加入驗證碼參數
- 後端係統的驗證接口需提供對驗證碼參數的支持
應用前麵的解決辦法可以得出下麵的開發和部署步驟:
- 修改後端係統的驗證接口,加入對驗證碼參數的支持,但為了兼容不帶驗證碼的前端係統(版本A),驗證碼參數是 可選 的
- 上線修改後的後端係統(版本B''),觀察是否與A兼容,如果有問題,回滾到版本B
- 修改前端係統,顯示驗證碼圖片和表單字段,在調用驗證接口時傳入驗證碼參數
- 上線修改後的前端係統(版本A'),觀察該版本是否工作正常,如果有問題,回滾到版本A
- 在前端A'和後端B''工作正常後,再修改後端係統的驗證接口,將驗證碼參數由可選改為 必需
- 上線修改後的後端係統(版本B'),如果工作正常,業務變更完成;如果有問題,回滾到版本B''
數據遷移的處理
在業務變更涉及數據遷移時,應對數據表的字段采取"隻增不刪"的原則。原因很簡單,當某個字段被當前代碼引用的字段被刪除後,線上業務是會出問題的,但新增一個沒有被當前代碼引用到的字段,則不會有問題。
等到確認新版代碼工作完全正常,不會再回滾到舊版本時,才將舊字段刪除。一旦舊字段被刪除,引用到舊字段的舊版本代碼就無法工作,也就無法回滾到舊版本了。
總結
- 使用容器化部署,代碼和配置可以整體回滾
- 通過引入中間版本,讓有依賴關係的係統可以分開獨立回滾
- 數據遷移時,不能刪除字段,要等到確認新版代碼工作正常,無需回滾到舊版時才能刪除
最後更新:2017-04-28 23:21:44