服務變更如何做到高可用?
近期,Cloudflare 在更新 WAF 配置規則時,因其中一個規則包含了正則表達式,導致 Cloudflare 全球機器上的 CPU 峰值使用率達到 100%,在最糟糕的時候,流量下降了 82%,對整個互聯網都產生了明顯的影響。
因此,變更的定義,不僅僅是狹義的上線新版本代碼,也應該包含配置變更,數據變更,操作系統變更,網絡變更,基礎設施變更等方面。變更是運維人員的主要工作內容,同時也是導致服務故障的主要原因。據 Google SRE 統計,線上 70% 的故障都是由某種變更而觸發的。
部署清單主要是管理部署期間的整個生命流程,通過將各個階段的各個步驟進行羅列和長期維護,從而逐步形成針對特定變更場景的說明手冊。
如果只是升級一臺服務器的二進制代碼,需要部署清單嗎?答案是肯定的。不能把二進制代碼變更等同于二進制文件替換,在替換動作之外,有很多的工作內容,僅僅是更新完畢以后,就需要考慮如下問題:
- 程序是否正常啟動
- 日志是否存在異常信息
- 服務功能是否正常
- 服務性能是否符合預期
- 服務關鍵指標是否異常
對于多模塊,多系統,多團隊配合的變更操作,如果沒有一份事前經過充分驗證的部署清單,誰在什么時候應該做什么事情,準入條件是什么,交付標準是什么,有哪些操作禁忌和注意事項,那這種復雜變更的結果就只能靠運氣了。
隨著運維自動化水平的提升,部署清單并不會消失,而是在載體上有所不同,從早期的紙質上線單,到現在內置于部署系統中,實現了更好的經驗傳承,校驗完善,流程管控,信息分享等。
絕大部分服務,都不應該由單個實例組成。那么,在變更的時候,就應該避免一次性升級所有實例,而應該分批次的逐步升級,并在每個批次間預留一定的時間間隔對上一批次進行觀察和評估,從而決定是否繼續進行升級,以此來保障變更的質量。
以 Google 為例,其灰度發布的比例,從 0.1% 開始,每 24 小時增長 10 倍推進,從 0.1%-> 1% -> 10% -> 100% (詳見 Google SRE 中文版 162 頁),并且灰度的初始比例一定不可以超過服務整體的冗余度。同時,在對服務進行變更操作的期間,需要將流量摘除,避免對線上產生影響,變更操作完畢后,方可引入灰度流量進行驗證。
在灰度階段,有針對性的選擇灰度流量,盡可能完整的覆蓋各類業務場景和用戶類型,并通過流量調度形成局部熱點,對服務的性能進行驗證,避免全量上線可能出現的性能下降。
變更操作一定要有回滾預案,并能夠快速回滾!日常的變更操作,只要有備份,大多數情況都可以進行回滾。那些無法進行回滾的,一般都是重大變更,這時候,等著你的基本上就是直接在線上調試并修 bug 以及超長的停機時間和大批的臟數據了。
不同公司對待回滾的態度不同,和其背后的專業能力有很大關系,因此不能盲從。如果對所有的回滾事件不加甄別的進行追責,那么導致的后果就是對于非核心故障,研發堅決不進行回滾操作導致帶傷上陣,或者說將回滾美其名曰快速迭代。
比回滾更高效的方案是功能開關,在發現新功能上線有問題后,可以通過功能開關立即關閉該功能,從而起到更快速的止損效果。可以想象一個場景,一次上線后,發現 10 個功能里面有 1 個功能異常,且引發了部分臟數據,因為還需要確保其余 9 個功能正常,因此不能全并發回滾,只能按照預置的并發度進行回滾,那么回滾耗時就會較長,這時候,如果有功能開關,那情況就大不一樣了。
既然線上有了變更保障能力,那為啥還要在線下費勁搞集成測試呢,直接在線上測不就行了嗎?我們假設這個觀點是正確的,那么所有未經測試的代碼全部推送到線上開始灰度,在灰度階段去發現各種問題,然后回滾,修復后繼續上線。但灰度的流量,也是真實的用戶,怎么能夠拿用戶的真實流量做這樣的事情呢。因此,線下測試還是非常重要的環節,通過線下測試,將 80% 以上的基本問題攔截在線下環節,在灰度環節,更多的去解決線下環境無法覆蓋的場景。
服務變更后,需要有一系列的基于部署清單管理的效果檢查的內容,例如前面提到的程序是否正常啟動,功能是否正常,性能是否正常,以及本次調整的內容是否符合預期,通過對變更的效果進行驗證,才能最終確認本次變更是否正確。同時,針對服務相關的全局核心指標的監控,在變更期間,既不應該出現異常,更不能被隨意屏蔽掉。
早期,Facebook 的交付工程團隊,會在每個工作日進行一次非關鍵性更新,而重大更新則每周進行一次,通常在周二下午進行。這里就體現了時間窗口的概念,時間窗口主要是用來降低變更導致的影響,常見的時間窗口有如下建議:
- 盡量避免節前做變更,即使是 BAT 和運營商,對于全年重要的節假日,往往會提前數周停止業務的非必要性變更,或者是將自動流程轉為審批流程
- 盡量避免在業務每天的高峰期做變更,例如很多網絡切割都是選擇凌晨進行操作,就是避免對業務產生影響
- 盡量避免在下班前尤其是周五下班前做變更,提前通告并全員值守的除外
如果服務是分組部署(多 AZ 部署、多 Region 部署),且分組間能夠做到盡量避免服務間的交互和基礎設施共享,那么在變更中,就需要利用該特性,對分組進行逐一升級和觀察,避免問題發生擴散,在出現問題的時候,通過流量調度即可快速摘掉流量止損。
任何的變更,都需要事前進行通告,告知相關的上下游團隊,變更時間,變更內容,可能的影響,應急聯系人等,并在變更期間的各個階段,進行通告。同時,也應該將變更信息錄入到統一的系統中,便于相關上下游訂閱。
本文以藍綠部署為基礎,介紹服務變更的優秀實踐
截圖簡要說明:將系統按照 AZ 的維度,獨立部署了 4 組,分別是 AZ1、AZ2、Z3 和 AZ4,這四組完全一致,基于隔離的思路,四個分組間,盡量避免了服務間的交互和基礎設施共享。
考慮到線上環境的復雜度,以及天然存在一定的冗余度,因此每次僅升級一個 AZ 分組。在第一個分組 AZ1 的時候,會進行較為詳細的驗證,除去常規的自動化檢查外,還會有測試人員的手工效果檢查,以此確保變更的質量。其余 AZ 因為變更內容一致,因此不會有測試人員的接入,僅保留自動化檢查。
如果變更存在問題,因選擇的 AZ1 是明確小于冗余度的,因此僅需要摘除流量后,再進行回滾,部分時候,如果研發要求短暫保留現場,也可以滿足其要求。
部署系統應該將變更的關鍵點內嵌到部署系統中,不斷完善,讓其成為變更流程無法逾越的環節,從而更好的保證變更質量。一個部署系統在做好單機部署工作的同時,也應該滿足如下業務側的需求:
- 提供部署清單功能,并具備自動化的檢查能力,階段性進展通告的能力
- 提供版本管理功能,常規變更(二進制代碼和配置)必須全部基于版本庫進行
- 提供快速回滾功能,能夠幫助業務快速回滾到上一個穩定版本,并能夠按照業務上下游編排順序進行回滾
- 提供時間窗口功能,默認不能夠在業務定義的黑名單時間點上線
- 提供備份功能,每次變更都需要將可能影響到的內容進行單機備份,便于快速回滾,默認是需要將上次的發布包進行全量備份盡量排除掉日志
- 提供灰度發布功能,能夠定義分組間和分組內的并發度,分組變更的暫停時長等
- 提供效果檢查功能,自動化的對業務進行預定義的各類檢查并和部署動作聯動,如暫停變更,繼續變更以及調整灰度的比例
- 提供編排功能,滿足多模塊的聯合上線
在配置變更的過程中,因配置文件錯誤,導致服務不可用,進而導致全局的服務故障,可能的原因有配置文件被截斷,配置文件合法性校驗缺失導致配置錯誤進程無法啟動,常見的故障:
- Nginx 配置文件錯誤導致網站整體不可用
- DNS 配置文件錯誤導致網站整體不可用
- 基礎服務如數據庫的授權白名單被清空導致多個業務服務異常
在規則變更的過程中,基于不同業務的規則生效順序不同,新增規則后可能會和原來的一些規則沖突,進而導致業務的異常,常見的場景:
- Iptables 規則,在現有的 100 條規則中新增 1 條