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