原文連結: https://url.hi-linux.com/0LB3T
我們每天要進行大量的線上變更操作。怎麽保證這些操作安全,不會導致故障,是我每天都在思考的問題。
這篇文章從工作經歷總結一些原則和想法,希望能有幫助。
線上操作有幾點基本的要求:
操作需要是可以 灰度的 (Canary):即能夠在一小部份範圍內生效,如果沒有問題,可以繼續操作更多的部份;
操作必須是可以驗證和監控的:要知道自己操作的結果,是否符合預期;
操作必須是可以回滾的:如果發現自己的操作不符合預期,那麽有辦法能夠回到之前的狀態;
邏輯很簡答:假設我一開始做操作範圍很小,可以灰度,做完之後我可以監控是否符合預期,如果不符合預期就回滾,那麽,操作就是安全的。
這三步中的每一步看似很簡單,但是實際做起來很難。
灰度
釋出過程是最簡單的一種灰度場景,現在有藍綠釋出模式:
分成兩組,將所有的流量切換到綠組;
先釋出藍組,此時是沒有流量的,釋出完成之後,將流量逐漸切換到藍組;清空綠組;
然後釋出綠組,釋出完成之後將流量切換到平均到兩組
還有捲動釋出,對於每一個例項:讓 Load Balancer 不再發給它新的流量,然後升級,然後開始接收流量,如果沒有問題,繼續以此處理其他的例項。
幾乎每個人都可以理解灰度的必要性,但是不是每一種操作都是可以灰度的。
比如說資料庫 DDL 的變更,很難灰度,送出到資料庫,資料庫就開始套用了;還有一些動態配置系統,一些全域配置,如果修改,就對所有的套用同時生效的;一般都是這樣一些資料來源型別的變更,很容易出現不支持灰度的情況。不可以灰度的情況也是最容易導致問題的。
一個替代方案是,搭建一套一模一樣的環境,在這個環境先套用變更,測試一下是否符合預期。但是在今天分布式環境下,很難模擬出來一模一樣的環境,可能規模小了,可能測試環境沒有一些使用者的使用場景,等等。總之,模擬的環境沒有問題,不能代表生產的環境就沒有問題。
最好的解決辦法,還是在軟體和架構,從設計上就能支持灰度。
驗證與監控
所有的操作,一定要知道自己在做什麽,效果是什麽。做完之後進行驗證。聽起來很簡單,但是實際上,很多人做事像是閉著眼睛,不知道自己在做什麽,做完之後有什麽效果也不管。
驗證操作的結果
舉一個例子,比如目前閘道器遇到了什麽問題,經過查詢,發現和 Nginx 的一個參數有關,然後根據網上的內容修改了這個參數,回頭去看問題解決了沒有。如果沒有,繼續在網上查資料,看和什麽參數有關。
上述操作,一個潛在的問題是,當問題真正修復了之後,我們不知道自己做了啥才修復問題的。也有一些時候,相同的配置變了名字,實際上這個修改這個參數是可以解決問題的,只不過我們用了從網上得到的過時的參數名字,所以不生效。
所以,對於每一個操作,推薦直接去驗證目前的操作結果。比如改了一個 log 參數,那麽直接去看這個參數是否生效,是否符合預期,然後再去看其他的問題是否得到解決。
做操作要一步一步來,做一步驗證一步。
另外,最好去驗證操作的副作用,而不是驗證操作本身。比如,修改了一個配置,不是去
cat
一下配置檔確認就可以了,而是要去看自己修改的配置是否真的生效了。比如路由器裝置,我們執行了一些命令
ip route ...
,驗證的方法並不是
show running-config
去看配置是否有這一條,而是要去看
show ip route
確定配置是否生效。
驗證核心的業務指標
除了驗證操作結果之外,也要關註業務指標是否還正常。
如果業務指標不正常了,而恰好和自己的操作時間吻合,那麽就應該立即回滾。
聽起來很合理?但是實際上,很多人(我也是)第一反應都會是,我的操作不可能引起這個問題,讓我先看看日誌,到底發生什麽了。
當發生問題的時候,時間很寶貴,正確的做法是第一時間在群組裏面宣布自己的操作(事實上,操作之前就宣布了,但是訊息太多,沒有問題的時候沒有人會認真看操作歷史),然後開始進行回滾。可惜的是,我發現這麽做的人很少,大部份都是想去排查,直到確定是自己的操作導致的,才開始回滾。
回滾
同上,不是所有的操作都可以回滾的。一些可以補償的方案有,操作上盡量設計成可以回滾的(有些廢話)。比如,DDIA 這本書就介紹了數據上如何做向前相容和回溯相容的方法。
舉個例子,比如軟體新版本的一個配置要從名字 A 改成 B,不要直接改,而是添加一個配置 B,程式碼裏面可以讀 B,如果沒有的話,嘗試讀 A。等升級完成之後,在下一個新版本中,去掉 A 的邏輯。這樣,每兩個版本之間都是相容的。
除此之外,還有一些我認為非常重要的東西。
操作計劃和操作記錄
一些復雜的操作,比如修改 DNS,配置閘道器,配置其他東西,可能是聯動的。而且顯示中也不是所有的東西都適合自動化的。這些復雜的操作,推薦在操作之前就寫好操作計劃,然後對著一步一步操作,貼上必要的驗證結果和操作時間。萬一出現什麽異常,就可以將異常出現的時間和自己的操作記錄對照,很有用的。操作計劃也可以相互 review,如果是 gitops 的話,就更好了。
效率
這是 Last but not least! 操作的效率至關重要。
我認為運維平台要設計成簡潔,沒有歧義,流程清晰的,非必要不審批。這可能跟直覺相反,尤其是領導的直覺。
領導(不知為何)覺得審批流程越多越好,出了事故就開始思考在哪一個階段可以加上一個審批流程,來避免類似的問題發生。但其實,我覺得流程越多,出問題的機率不減反增。
程式設計師天生就不喜歡繁重的流程,如果流程太重,就會出現其他的問題,比如,人們會想辦法繞過不必要的流程;會想辦法「搭車釋出」(意思就是將多個操作合並成一個,這也是違反原則的,一次應該只做一個操作);對於明顯出現異常苗頭的時候,因為不想重新走審批而鋌而走險。
但是出現這種情況,領導不會覺得流程有問題,領導會覺得你小子不按照流程辦事,開除。
最後導致 SRE 的幸福感很低,事情還是要那麽多,完成工作不得不鋌而走險,還得責任自負。
事實上,真正能保證安全的是架構設計簡單,做事的人知道自己在做什麽,操作按照如上灰度、驗證,出問題回滾,而不是靠流程。SRE 之間 Review 是有價值的,審批是沒有價值的,大部份的審批僅僅是請示一下領導而已,領導可能看不懂操作的後果是什麽。
所以,流程是有代價的。
往期推薦
!
點亮,伺服器三年不宕機