肝完這篇穩(wěn)定性建設(shè)萬字總結(jié),誰還吐槽我線上不穩(wěn)定!
俗話說“缺啥補啥”。想起寫這么一篇文章,不是因為自己和團隊穩(wěn)定性建設(shè)做得有多好,相反,最近經(jīng)常被吐槽線上不“穩(wěn)定”......
回想當年,作者在某度第一個項目中,從0到1擼了一個多月的碼(檢索模塊c/c++)。后面QA測試N輪,硬是沒能提出幾(yi)個有效bug,線上似乎也沒啥動靜?,F(xiàn)在卻被人指責穩(wěn)定性做得不好,這事兒看起來不能忍。
“穩(wěn)定”這個詞,從用戶到ZF機關(guān),一線研發(fā)到大老板,大家似乎都會經(jīng)常提及。不過作者發(fā)現(xiàn),他們所謂的穩(wěn)定性,也不見得就是一回事。網(wǎng)上搜了搜,沒看到有什么公認的定義,系統(tǒng)論述這個話題的文檔也不多,講實戰(zhàn)的倒是不少。本文中,作者試圖做個相對“系統(tǒng)”的論述,重點討論“服務(wù)穩(wěn)定性”是什么,應(yīng)該如何建設(shè)。作者之前經(jīng)歷絕大部分時間都在做后端開發(fā),能力和視野所限,難免會偏服務(wù)端。
相比于“系統(tǒng)性”,很多優(yōu)秀的程序員都只喜歡聽所謂的“干貨”。在“系統(tǒng)性”和“干貨”之間不斷地糾結(jié)中,作者艱難地完成了本文。
全文基本沒什么新鮮玩意,很多都是老生常談,也借鑒了非常多的來源。作者只是努力整理并重新組織在了一起。因為來源太龐雜,我就沒法一一例舉相關(guān)出處,如有侵權(quán),請聯(lián)系作者刪除。這里一并謝過執(zhí)導過我,幫助過我和分享自己的知識到互聯(lián)網(wǎng)的所有大佬們!
我們都在聊什么
“穩(wěn)定性”其實還挺難定義的。讓我們先看幾個英文單詞:Availability, Reliability, Stability。
- Availability
經(jīng)常被翻譯成可用性??吹竭@個單詞,相信大部分人腦子里應(yīng)該都會呈現(xiàn)很多個9??磮D1,4個9的穩(wěn)定性意味著一年宕機時間不能超過53min,其實是非常難的。可用性這個概念關(guān)注的是系統(tǒng)故障時長。實際上,我們平常會更關(guān)注這個宕機時間如何定義的。很多人說自己服務(wù)可用性是99.99%,不要輕易相信。你去幫他review下,會驚喜地發(fā)現(xiàn),他可以通過宕機時間本身的定義任意調(diào)整這個值。所以如果是上下游關(guān)系,還是先把這個指標定義清楚再聊別的會比較好。常見的定義舉例:影響核心功能(e.g.下單)成功率20%以上所持續(xù)時間等等。這里的X%還挺重要的。后面的討論中,我們可以依據(jù)這個百分比,設(shè)計我們的灰度方案等。以免發(fā)布個小流量,還搞出P0,不合適。
圖1 N個9的穩(wěn)定性
- Reliability
經(jīng)常被翻譯成可靠性。相對于可用性,可靠性關(guān)注的可能會更泛一些。在服務(wù)化的場景下,大家會經(jīng)常提到SLA。SLA是對一個服務(wù)可靠程度的相對量化的約定。其中就可以包括服務(wù)可用時長、接口響應(yīng)時間(如99分位)、錯誤率、集群吞吐率等等。SLA建議盡量用書面形式提供,并且服務(wù)提供方和調(diào)用方一同簽字畫押。一般還有配套的獎懲措施才能工作的更好。簽字畫押,是為了后面少扯皮。很多時候,處理線上事故總是沒有事故定責時候來的令人緊張刺激。
如果下游沒有提供明確的SLA,我們就得自己根據(jù)歷史數(shù)據(jù)猜測下游各項指標,以便寫出還算合理的代碼,比如超時時間、重試次數(shù)、限流大小等等都跟下游服務(wù)能力密切相關(guān)。當然下游也是動態(tài)的,如果對方都無法提供明確的SLA,那其實大家都挺難的。咱們自己提供的服務(wù),最好都有明確的量化指標,隨時提供給上游。如果給不出來,說明我們對自己服務(wù)還不夠了解,沒有足夠的掌控能力。
如果是內(nèi)部系統(tǒng),老板還會經(jīng)常關(guān)注線上問題數(shù)量和等級分布等。處理P0事故緊不緊張?這些都是在努力量化一個系統(tǒng)的可靠程度。
- Stability
一般翻譯成穩(wěn)定性。通常是指一個系統(tǒng)如果輸入保持不變,輸出也不會隨著時間發(fā)生變化。但是這個穩(wěn)定性,大概不是我們經(jīng)常在討論的穩(wěn)定性。你會發(fā)現(xiàn)歪果大佬們一般討論“穩(wěn)定性”的時候喜歡用Reliability,而國內(nèi)大佬們卻喜歡用“穩(wěn)定性”。yy一下,這很可能又是個中國特色的表述了。大概來自于前輩們對我dang“維穩(wěn)工作”的深刻印象。你會發(fā)現(xiàn)我們所謂的“穩(wěn)定性建設(shè)”跟傳統(tǒng)意義上的“維穩(wěn)工作”基本思路是驚人一致的。監(jiān)控,隔離,應(yīng)急處置,特殊事件保障,演練,宣傳培訓等等,請各位客官自行發(fā)揮想象力...只是互聯(lián)網(wǎng)環(huán)境下,我們不太可能期待“輸入不變”。而是,在輸入經(jīng)常不確定,且系統(tǒng)在不停地迭代的情況下,確保新老輸入都能在預(yù)期的時間內(nèi)得到令用戶滿意的結(jié)果。
作者認為,其實概念可能也沒那么重要?!胺€(wěn)定性”這個詞兒似乎也很貼切,有點中國特色挺好。穩(wěn)定性建設(shè)的關(guān)鍵是,我們得找到一套大家都認可的指標來衡量他。對于相對獨立的服務(wù),作者推薦用SLA去約定一個服務(wù)的穩(wěn)定性,并盡最大努力達成這個承諾。對于服務(wù)提供方,SLA不僅是一個承諾,更是對自身量化的要求。當我們都不敢做出承諾的時候,又何談穩(wěn)定性建設(shè),何談責任與成長?至于怎么定義一個“服務(wù)”,一是看業(yè)務(wù)邊界,二是看組織架構(gòu)。很多時候組織架構(gòu)決定系統(tǒng)架構(gòu),而SLA制定過程也跟組織架構(gòu)密不可分。對于終端團隊,我們可以在SLA基礎(chǔ)上做一些擴展,比如增加一些體驗相關(guān)指標。有時候個別后端服務(wù)掛了,可以做到對用戶無感,反而APP經(jīng)常crash那可能是個災(zāi)難。所以,穩(wěn)定性也得分層去看。
1)Dickerson的可靠性層次模型
其實作者之前也沒聽過該大佬。為了準備這邊文章無意中搜到的。他據(jù)說是前谷哥SRE團隊成員。然后后人在谷哥SRE電子書中引述了相關(guān)模型。大佬也是借鑒了馬斯洛需求層次模型。馬老師的這個模型中表示,想得到上一層的滿足,你得先保證其下一層已經(jīng)得到了很好的滿足,否則容易“出事兒”。比如,當我們都沒飯吃了,哪兒還會去關(guān)心哪個行業(yè)更卷呢?當然當我們很好地實現(xiàn)了某一層,那下一層需求就會是我們最大的動力來源。
圖2 馬斯洛需求層次
參考M老師的模型,D大佬提出了他的穩(wěn)定性層次模型,以便幫助SRE團隊更好的保障系統(tǒng)穩(wěn)定性。
圖3 Dickerson可靠新層次模型
在D的模型中,他從SRE的視角出發(fā),將穩(wěn)定性建設(shè)也分了7層。
- 他認為穩(wěn)定性建設(shè)最基礎(chǔ)是監(jiān)控(Monitoring)。沒有監(jiān)控,一個服務(wù)是否穩(wěn)定無從談起。我們首先得知道服務(wù)運行情況,當系統(tǒng)哪里出了故障,我們需要及時發(fā)現(xiàn)(告警)。
- 當獲知系統(tǒng)出故障后,SRE們需要作出一些應(yīng)急響應(yīng)(Incident Response),包括24小時on-call機制,系統(tǒng)降級預(yù)案,協(xié)同相關(guān)方進行進一步分析,定位最終原因并修復(fù)上線。
- 事后,還需要組織進行深度復(fù)盤和根因分析(Postmortem/Root Cause Analysis)。我們需要做到從失敗中學習,并盡量保證未來不會掉進同樣的坑。
- 前三步都是在做一些防御工事,我們應(yīng)該盡量在測試階段就發(fā)現(xiàn)問題,并通過科學的發(fā)布過程來保證不會輕易引入新的線上問題(Testing+Release procedures)。
- SRE們還需要關(guān)注容量需求的變化情況(Capacity Planning)。系統(tǒng)是動態(tài)的,我們需要盡力做到讓資源在適當?shù)臅r機,能夠靈活的調(diào)配到真正需要他的地方。
- 以上做好之后,還需要關(guān)注一些研發(fā)的工作(Development)。這部分包括原先的系統(tǒng)實現(xiàn)是否合理,從問題反推,是否可以有更合理的設(shè)計,并推動優(yōu)化。當然還有一些必要的工具也需要開發(fā)。
- 穩(wěn)定性最終極要關(guān)注的是產(chǎn)品本身(Product)。從用戶角度,穩(wěn)定性意味著什么?哪些是他們核心關(guān)注的?我們應(yīng)該努力通過產(chǎn)品和流程設(shè)計等減少用戶對系統(tǒng)故障的感知,甚至做到無感。
2)本文討論框架
可能大部分國內(nèi)互聯(lián)網(wǎng)公司沒有真正的SRE團隊。即使有這樣的團隊,據(jù)我所知他們可能更關(guān)注一些更宏觀的穩(wěn)定性建設(shè)。日常的服務(wù)級別的線上穩(wěn)定性保障,一般都是由研發(fā)團隊主要負責的(一般是事故主要責任方)。因此本文中從一個一線研發(fā)團隊視角出發(fā),去討論穩(wěn)定性建設(shè)該如何做。
事實上不管是R&D還是SRE團隊,要關(guān)注的問題是相同的,只是視角略有不同。既然上面鋪墊了這么多,作者也參考D大佬的層次模型,引出下面的穩(wěn)定性框架圖(向大佬們致敬)。當然所謂框架,也沒什么新意,更多是方便我后續(xù)組織文章。
圖4 本文討論的穩(wěn)定性建設(shè)框架
在上圖的框架下,雖然也有分層,但跟D不同,作者認為沒有誰比誰重要或者上層強依賴下層關(guān)系。只是為了討論方便可以分層去看。傳說中的“既要也要還要”,總是那么的“正確”。我們很難在這些層次上進行取舍,只能說都很重要。作為一個R&D工程師,我們需要時刻關(guān)注所有這些方面的問題,最多可以根據(jù)自己團隊當前狀況和急迫程度判斷優(yōu)先級。下面會逐個去討論。
穩(wěn)定性建設(shè)該如何做
因為篇幅和視野限制,本文無法求全,也不太可能非常深入。如果能拋磚引玉,作者就很開心了。
1、梳理
梳理其實可以沒有,理想情況是我們對自己的系統(tǒng)一直都非常熟悉,知道他是怎么工作的,目前他還存在什么問題。但現(xiàn)實可能是:
- 我們一直在非?!爸钡亍鄙现€,周而復(fù)始。因為“著急”,我們當時做了很多折中,做了很多臨時的事情。說好的后面優(yōu)化,一直都還在后面。甚至因為人員輪換,可能都已經(jīng)不記得當時埋了哪些雷;
- 可能你剛接手了一個新的系統(tǒng)(和團隊)。當然,你也可以理解梳理為一種復(fù)盤。只是他可能沒辦法那么頻繁。
那我們需要梳理什么呢?這個其實沒有標準答案,得看系統(tǒng)和團隊當前情況而定。下圖針對一般情況羅列了一些常見的梳理項??梢愿鶕?jù)實際情況進行增減。這也適用于我們快速去熟悉一個新接手的系統(tǒng)。
圖5 梳理
梳理的過程很多時候都不是一個人可以完成的。我們需要協(xié)調(diào)很多人參與進來,并進行集中串講,共同分析等。不要一梳理就梳理幾個月。類似迭代開發(fā),我們也可以逐步去梳理,甚至還需要跌帶著去做。當一個團隊人員流動比較大時,新人串講也是挺好的一個時機。
當一個相對理想的梳理工作完成之后,我們大概能知道當前系統(tǒng)現(xiàn)狀是什么,有哪些穩(wěn)定性隱患。很多時候知道隱患在哪里,比排除和優(yōu)化更重要。剩下的就是按優(yōu)先級排期逐一解決了。梳理本身也會幫助我們重新審視自己的系統(tǒng),加深對他的理解。這對于后續(xù)迭代開發(fā),線上問題跟進等都有莫大的好處。所以,當覺得自己團隊沒事兒干的時候(往往都是錯覺),可以讓大家多去梳理(串講)一遍自己的系統(tǒng)。
這一步,還有個重要產(chǎn)出是:哪些業(yè)務(wù)指標是需要重點關(guān)注的,核心接口有哪些。這部分在下一節(jié)中會重點討論。
2、監(jiān)控&Trace
1)監(jiān)控
監(jiān)控大家應(yīng)該都不陌生。在上文中我們也梳理出來了當前服務(wù)核心指標和核心接口都有哪些(新項目應(yīng)該是在設(shè)計階段就應(yīng)該定義好)。我們需要重點圍繞這些指標和接口進行監(jiān)控建設(shè)。監(jiān)控主要目標是當服務(wù)異常時,我們能第一時間感知,以便盡早介入,盡快止損。另外,通過合理的監(jiān)控設(shè)計,我們還可能盡量的縮小問題范圍,幫助我們定位問題根因。缺失有效監(jiān)控,我們就是個瞎子,每天都掉坑也是正常的。
監(jiān)控大致可以分成三層去看,本文只討論業(yè)務(wù)層。
- 核心業(yè)務(wù)指標監(jiān)控
這個經(jīng)常不被重視,但他卻是最重要的。我們應(yīng)該首先站在業(yè)務(wù)視角去看到底應(yīng)該關(guān)注哪些指標,然后再去想辦法監(jiān)控這些指標。既然說是業(yè)務(wù)指標,肯定就跟業(yè)務(wù)本身有關(guān)了,所以各個系統(tǒng)可能都不一樣。舉例,對于一個訂單系統(tǒng),那么我們關(guān)注的核心指標可能有:下單量、成單量、取消量、超時未支付量等等。然后我們想辦法對這些指標進行準實時監(jiān)控。當這些指標有明顯異常,可以即刻發(fā)出告警。
當業(yè)務(wù)數(shù)據(jù)較為稀疏時,秒級監(jiān)控可能經(jīng)常會誤告警,我們可以適當把時間窗口拉長一點看,比如降級為分鐘級監(jiān)控。甚至我們可以根據(jù)業(yè)務(wù)高峰期等自動調(diào)整監(jiān)控周期。
這里核心是如何定義好一個指標。當指標定義明確,以咱們的聰明才智相信總能有辦法監(jiān)控他,并且總能找到一些報警策略(不行上AI),使其足夠靈敏,誤報警概率也還能接受。常見的監(jiān)控手段包括基于log和數(shù)據(jù)庫binlog的監(jiān)控。極端一點的情況,我們可能需要在業(yè)務(wù)代碼里單獨為這些指標打log(記文本或?qū)憥?。所以說,監(jiān)控設(shè)計也是系統(tǒng)設(shè)計的必要組成部分,最好前期就考慮好。
- 核心接口監(jiān)控
接口監(jiān)控應(yīng)該不用我多說。重點就那三個指標,QPS、延遲和錯誤率。這里錯誤率的統(tǒng)計,對于錯誤碼規(guī)范有要求以外,其他基本都是標配。做細致一點,需要對接口調(diào)用方單獨做監(jiān)控。比如接口QPS突然飆升,我們需要盡快知道到底是哪個來源。
- 下游依賴監(jiān)控
下游可能是服務(wù)提供方、也可能是個中間件。中間件一般都有單獨團隊維護,他們會提供通用的監(jiān)控大盤等。業(yè)務(wù)方要做的更多是從自己的視角看這些被依賴方他的實際運行情況如何。因為絕大部分依賴都是通過RPC進行的,所以類似接口監(jiān)控,我們需要關(guān)注下游調(diào)用成功率,響應(yīng)時間等等。當然如果下游都提供了監(jiān)控大盤,可以考慮把兩者合并一下,找起來方便。
- 監(jiān)控大盤
呈現(xiàn)很多時候都挺重要的,就像如果有人PPT寫得好,你不能否認他其他方面也大概率比咱更優(yōu)秀。為了看起來方便,我們需要分層去建設(shè)監(jiān)控大盤。每個大盤也不能太大了。大盤在線上走查,上線回歸等場景必不可少。這里沒什么新鮮的,把分層設(shè)計好就差不多了,不啰嗦了。
2)告警
告警策略其實可以復(fù)雜到很多大佬都在談AI了。常見的就是同比異常、環(huán)比異常、超閾值等。策略核心就是在召回和準確性之間各種折中。作者的觀點是寧可誤報,不能漏報。誤報得多了,我們自然就有動力去優(yōu)化了。至于告警方式,傳統(tǒng)的,電話、短信為主,釘釘、email為輔。報警內(nèi)容一定要盡量多的帶一些具體指標項和數(shù)據(jù)等(注意信息安全,運營商你們懂得),以便我們快速判斷問題嚴重性。
很多時候,我們報警策略本身可能也會不穩(wěn)定,也可能設(shè)計得不夠靈敏。這時候就要求我們?nèi)ブ鲃尤パ惨?。比如上完線,都去看看大盤是否有異常,值班同學每天定時掃幾眼(尤其高峰時)。當然機器和服務(wù)太多了,無法人肉去看大盤時,也可以搞一些自動巡視腳本提效。
3)Trace
他可以有個高大上的名字“根因分析系統(tǒng)”。通過監(jiān)控,我們知道系統(tǒng)有問題了,這個還不夠。當我們及時止損之后,應(yīng)該抓緊定位根因。trace系統(tǒng)一般依賴系統(tǒng)日志采集,并通過二次索引,提供快速的查詢線上問題和統(tǒng)計分析的能力。通過trace,我們除了追蹤單個請求鏈,還可以生成系統(tǒng)整體拓撲,系統(tǒng)熱點分析,整個鏈路性能分析等等。這里log設(shè)計和規(guī)范是最關(guān)鍵的。如果系統(tǒng)里的logid(traceid)都還沒打通,團隊都不知道spanid是個啥的話,那工具其實也可能還不重要。當然最好是這些都在框架層面就解決了,沒必要讓每個程序員都關(guān)注他們的存在(除定位問題時候以外)。最終,trace還是需要有個強大的配套工具支持的。這個數(shù)據(jù)量可能會很大(降級為采樣?),分析效率又很關(guān)鍵,沒有好用的工具,全靠寫腳本很多時候都不現(xiàn)實。
3、應(yīng)急處置 & Case Study
1)應(yīng)急處置
說白了就是線上問題處理。因為每個系統(tǒng)設(shè)計和現(xiàn)狀,甚至每次遇到的問題都不一樣,所以很難搞出一套通用的機制或方法論。這里只是簡單聊一聊一些思路。
① 責任人
當線上有問題,我們首先得有明確的責任人去跟進。如果是監(jiān)控告警發(fā)現(xiàn)的問題,那么誰收到告警,誰就應(yīng)該是那個責任人(不怕多,就怕沒人跟)?!笆讍栘熑沃啤甭犨^的朋友大概也能知道我在哪兒被蹂躪過了....其他情況,通過值班機制等保證每個關(guān)鍵時間段(比如高峰期),都有明確的人能及時跟進。每個團隊情況不同,可以自行設(shè)計。這個值班人可能是研發(fā),可能是SRE,也可能是個技術(shù)支持之類的。
② 判斷影響面
作為責任人,首先要做到遇事不慌,快速判斷影響面。看核心業(yè)務(wù)大盤是否受影響。影響了核心業(yè)務(wù),那就立刻需要升級處理。緊急問題應(yīng)立即通報。如果業(yè)務(wù)大盤影響不大,那其他報警叫得再歡,咱們其實也不虛(再論監(jiān)控的重要性)。一般問題,可以考慮進一步確認影響,或者直接跳到“找根因”環(huán)節(jié)。
③ 通報
需要明確緊急問題通報范圍,讓更多的人參與進來協(xié)助處理緊急狀況。其中至少要包含自己leader。
④ 止損
通報后,緊急事件應(yīng)優(yōu)先考慮止損。
- 近期有相關(guān)上線,優(yōu)先考慮回滾(比如時間點比較接近,或改動跟該功能有關(guān))。
- 如果是流量突增,那應(yīng)該考慮限流+緊急擴容。
- 如果是下游服務(wù)異常,那么應(yīng)該考慮降級。
- 如果單個集群問題,考慮切集群(機房)。這里,你會發(fā)現(xiàn)各種case,其實是無法枚舉完的。
唯一共同點是,每次事故原因,起初看起來都很迷,最后定位后都很傻X,而且總是驚人的相似。所以應(yīng)急預(yù)案,需要平時積累,現(xiàn)場去想,大概率就遲了。預(yù)案主要是依據(jù)歷史事故和架構(gòu)師們的經(jīng)驗,不斷積累的過程。每個業(yè)務(wù)不同的故障預(yù)案都不同。上面止損里簡單描述了集中常見故障及處理預(yù)案。作者想強調(diào)的是,預(yù)案不應(yīng)該只是文本,而應(yīng)該是經(jīng)過驗證的(演練過)極簡操作步驟,最好是已經(jīng)工具化(e.g. XX腳本)的。
⑤ 找根因
當我們有效止損之后,應(yīng)該把精力放在尋找跟因上。如果發(fā)現(xiàn)無法快速止損,也別太執(zhí)著了,至少可以分一部分人力找根因了。定位問題,有時候看起來是一門玄學,大神一出馬,往往很快就能破案。而且你會發(fā)現(xiàn),大神總是那幾個人。他們?yōu)槭裁幢仍劭炷兀课蚁?,首先肯定不是因為他代碼寫得好,也不見得有咱寫得多(某些人眼里的“技術(shù)?!?。而是,他對系統(tǒng)更熟悉,他了解系統(tǒng)整體架構(gòu),知道哪里是一些脆弱環(huán)節(jié),容易出問題,上下游依賴情況怎么樣,哪個下游比咱還不靠譜;他經(jīng)常去聽各種復(fù)盤,知道類似的問題之前出現(xiàn)過,是什么原因?qū)е碌模凰麑Ω鞣N工具更熟悉,比如trace,監(jiān)控系統(tǒng)等,所以效率更高。慢慢的他們就形成了一套自己的方法論,甚至可以從現(xiàn)象猜測出幾個最可能的原因,然后去逐一驗證??梢?,平時積累非常重要,要對自己所用的框架,所負責的模塊上下游都要做到盡可能多的了解,甚至去多讀一讀他們的源碼。
線上如果有穩(wěn)定復(fù)現(xiàn)的環(huán)境,可以下線一臺服務(wù)器專門定位問題。如果線上無法快速定位,可以考慮線下復(fù)現(xiàn)。所以線下鏡像環(huán)境也是很重要的。一方面,可以用于平時線下測試,當線上有問題時候,也可以用來復(fù)現(xiàn)問題。能復(fù)現(xiàn)的問題,其實就沒什么難度了。最后,大家一定要相信,沒有什么問題是無法定位的,事實也是如此。
很多時候無法定位,都是缺少關(guān)鍵日志,所以要養(yǎng)成各種異常分支都需要打個日志的好習慣,我們開始時候不要怕日志多,告警多,等我們無法容忍的時候總會有人去優(yōu)化他。但是一旦少日志,沒告警的時候就欲哭無淚了。
根因找到之后,我們需要上線驗證,并統(tǒng)計和修復(fù)損失了。
2)Case Study
其實是一種特殊的復(fù)盤。每次的線上問題,都是我們成本最高的一次學習機會。所以,一定要珍惜,要認真對待。相信大家也經(jīng)常做,所以具體復(fù)盤模板這些就不用我多說了,相信每個公司都有自己的一套。幾個tips:
1)不要把Case Study搞成批斗大會。雖然定責很重要,但是不用太糾結(jié)這個。我們得有一套相對客觀的定責標準,省得有人糾結(jié)這個。比如之前我們就約定線上事故由源頭負主要責任(很多時候是全部),什么上游保護下游,上游限流沒生效,上游沒合理重試這些都是額(che)外(dan)的。還是得想方設(shè)法保證自己不掛,掛了就得認。我們更多要去想怎么從失敗中學習,不斷完善自己的系統(tǒng)。我能想得到唯一需要我們保護的下游可能是MySQL,因為他實在太老,太脆弱了,可得對她溫柔一點。
2)圍繞根因要多去想是否還有其他類似隱患,要真正做到舉一反三,比如排查其他模塊是否有類似問題,比如拉上上下游關(guān)聯(lián)系統(tǒng)一起看怎么全鏈路優(yōu)化,比如故障期間產(chǎn)品提示等是否可以更友好一點等等。
3)對于發(fā)現(xiàn)的問題要做好保護:
- 監(jiān)控配置和日志打印是否需要優(yōu)化?以便下次有類似問題不用這么辛苦去定位。
- 相關(guān)代碼是否需要重構(gòu)?
- 測試用例增加了嗎?
- 線上問題預(yù)案是否需要增加相關(guān)條目?
4、測試&發(fā)布
1)測試
質(zhì)量跟穩(wěn)定性很多時候都是劃等號的。質(zhì)量保障是整個軟件工程核心活動,是研發(fā)人員的職業(yè)底線。對于工程團隊,如果這個底線沒守住,那其他努力都將變得黯淡無光。我們必然要竭盡全力,讓問題在上線發(fā)布前就發(fā)現(xiàn)并解決了。
測試如此重要,以至于國內(nèi)很多互聯(lián)網(wǎng)公司都有專職的QA團隊。當然,即使有了QA團隊,測試工作也并非全部由該團隊完全負責。研發(fā)人員要對自己編寫的代碼負全部責任,有沒有QA團隊都一樣。設(shè)有QA團隊,有提測這些額外的流程,更多是為了再多一層保障。
作者沒有實際研究過QA團隊自己是如何定位并規(guī)劃他們團隊的工作的,所以以下都是站在研發(fā)角度講的,理解有偏差的請見諒。因為測試相關(guān)話題太大了,這里只是簡單羅列一些常見的測試類型。至于怎么做,如何算做得好這個估計得再好好學習學習才行。
① 單元測試(Unit Testing)
指單個函數(shù)、模塊或功能級的測試,屬于白盒測試。一般都是由研發(fā)人員自己完成。敏捷團隊應(yīng)該都了解測試驅(qū)動開發(fā)(TDD)。在一些傳統(tǒng)軟件行業(yè),如通信領(lǐng)域等可靠性要求較高的單位可能工作的會相對好一些?;ヂ?lián)網(wǎng)領(lǐng)域,尤其其中做上層業(yè)務(wù)開發(fā)的,真正把TDD用得好的并不多。不過一些思想值得我們時刻參考。要想把單測寫好,維護好其實并不那么容易。首先,寫出來的代碼,得對測試友好。這對于編碼能力是有一定要求的。往往抱怨單測很浪費時間的,大概率是代碼抽象,尤其接口層面設(shè)計,分層這些沒有做好的那些人。另外,測試用例需要維護,是有成本的。甚至測試用例的代碼量會遠遠大于業(yè)務(wù)代碼。不過要知道自動化測試用例,不是為了一次功能測試而編寫的,更多是一個文檔和一種保護。保護測試好的代碼不會被后人輕易破壞。他可以反復(fù)、全自動執(zhí)行,所以疊加起來的價值可以很大。有了自動化測試用例,我們就可以在每次代碼變更時候,都可以自動跑一下這些case。這個屬于check in build的一部分。因為case數(shù)量會越積累越多,我們?yōu)榱瞬挥绊戦_發(fā)效率,可以把這些case分成快速的和全量的??斓氖敲看蝐heck in都會執(zhí)行(check in build),慢的可以是天級執(zhí)行(daily build)。
② 集成測試(Integration Testing)
指將已經(jīng)完成了單元測試的模塊等組合起來測試,比如接口測試,某個流程測試等等。他一般針對某個功能點(特性)進行測試,通常屬于黑盒測試。研發(fā)內(nèi)部的聯(lián)調(diào)測試,QA的大部分測試工作,都屬于這個范疇。
③ 系統(tǒng)測試(System Testing)
指從交付角度(用戶視角)進行的更宏觀的測試。操作系統(tǒng)適配測試,低端機適配測試,弱網(wǎng)測試,安全測試,性能測試,壓力測試等等,都可以歸為系統(tǒng)測試大類。
④ 回歸測試(Regression Testing)
當系統(tǒng)有變更時,我們通過回歸測試保證原有功能都沒有被破壞。一般分為線上和線下,而且希望這部分自動化程度越高越好??咳斯とプ龌貧w測試將必然是個悲慘的故事。
⑤ 冒煙測試(Smoke Testing)
據(jù)說是最早做板子的前輩們,在設(shè)計好一塊板子之后先通電看看會不會哪里冒煙。如果冒煙就說明根本沒必要進行任何其他測試了,直接回爐重造。在軟件行業(yè),一般指的QA團隊的準入測試吧。一般要求他能自動運行,且速度要快一些。冒煙沒通過,直接打回提測流程。
⑥ α測試(Alpha Testing)
一般是指客戶側(cè)在正式交付前的驗證測試。不過互聯(lián)網(wǎng)行業(yè)很少提這個了。
⑦ β測試(Beta Testing)
將產(chǎn)品交付給少部分用戶,然后進行實際場景應(yīng)用,并收集反饋。我們一般叫小流量測試或灰度測試了,換了個名字。
⑧ 壓力測試(Stress Testing)
測試一些臨界壓力情況下的系統(tǒng)表現(xiàn)。比如系統(tǒng)最大同時在線的用戶數(shù),最大支持的輸入大小,模擬用戶惡意下單等等。一般是針對系統(tǒng)級的全流程測試。當然如果某個接口很重要,有時候也會說做接口壓測,實際上就跟下面的性能測試有點混淆了,不過這個不重要。在to C場景,壓測是非常重要的,如果有一套成熟的壓測體系,那恭喜你,至少心里會踏實很多。當然搞一套有效的壓測體系,我們也需要不小的投入??赡軙媾R的幾個挑戰(zhàn):
- 壓測工具本身并發(fā)度是否可以達到我們的要求?
- 壓測請求如何模擬,線上錄制?簽名、token這些都很麻煩。
- 壓測流量如何標記?
- 提交接口怎么壓?產(chǎn)生的很多“垃圾數(shù)據(jù)”如何清理,如何跟真實數(shù)據(jù)隔離會是個大麻煩(影子表?)
- 全鏈路壓測,涉及到多個團隊,甚至是多個部門協(xié)同。如果要做架構(gòu)升級(比如增加流量標記),那可能至少都是按月計的。壓測期間很可能還會影響線上服務(wù),深夜也有用戶咋辦?
⑨ 性能測試(Performance Testing)
比如某個接口的單機性能,集群性能等。
⑩ 故障演練(Recovery testing)
模擬各種故障,比如下游宕機,數(shù)據(jù)庫離線等等,然后看系統(tǒng)表現(xiàn)是否跟設(shè)計一致??梢哉J為是系統(tǒng)級的異常測試。Recovery testing還會關(guān)注當故障恢復(fù)后,系統(tǒng)是否可以自動復(fù)原。
還有很多名詞,有的作者也沒接觸過,就不再發(fā)散了。
2)發(fā)布
據(jù)不完全、不可靠統(tǒng)計,70%以上的線上事故是由代碼變更(包括配置)引起的。可見把測試好的代碼發(fā)布上線是一個非常高風險的事情。為了盡量降低這個風險,人們搞出了各種各樣的灰度策略和機制。他的本質(zhì)是:1)開發(fā)和測試人員沒能測到的問題,就讓更多的用戶幫我們測試(眾測);2)為了控制影響面,需要逐步放量,爭取在最小的影響面下發(fā)現(xiàn)問題。下面簡單介紹下常見的幾種灰度方案。
① 金絲雀發(fā)布
礦工的故事大家應(yīng)該都聽過了,不再贅述。其實很多時候我們所謂的灰度發(fā)布,基本就是等價于金絲雀發(fā)布了。通常我們會把集群分成幾個集群,典型的預(yù)發(fā)布、小流量和全量集群(當然可以有更多級)。然后,逐步放量。其中預(yù)發(fā)布一般不對外,我們把代碼上到預(yù)發(fā)布環(huán)境,通過自動化回歸腳本+人肉,進行新老功能的回歸。如果有內(nèi)測環(huán)節(jié)那就更好了,找一些公司內(nèi)部的用戶幫忙驗證一下。到小流量環(huán)境是要有真實的公網(wǎng)流量的。我們一定要預(yù)留足夠的時間來收集反饋。當然具體時間是根據(jù)版本大小和廠子現(xiàn)狀定的。收集反饋最核心就是之前建好的監(jiān)控大盤了。如果能收集真實的用戶反饋那就更好了。VoC自動檢測,其實也算監(jiān)控一種吧。比如直播系統(tǒng),用戶刷屏“卡”“卡死”...
金絲雀發(fā)布估計是用的最多的一種發(fā)布方式。其核心是制定一套分流機制。最簡單就是在router層按流量隨機分流了。如果你的服務(wù)只跟流量本身有關(guān)(典型的就是不用登錄的場景,如百度搜索),那用服務(wù)器灰度就夠了。1臺,10%,100%...如果想根據(jù)用戶分流(要求一個用戶要不用舊版服務(wù),要不就用新版的),那么就得需要一些設(shè)計,典型的是在HTTP頭里增加一些分流標識等。如果再復(fù)雜的分流策略,那么就得自己搞個gateway了。有集中存儲的時候,比如MySQL,那么存儲層面要不要也分開,也是個問題。
客戶端在各大應(yīng)用市場的發(fā)布策略,一般也都屬于這一類。
② 藍綠發(fā)布
很少用。大致思想是搞兩套集群,藍色是老的,新的是綠的。起初流量指向藍的,等把代碼部署到綠的,驗證ok之后把流量指向綠的。下一輪發(fā)布,把顏色交換一下。好處是回滾快,成本就是多了100%的冗余。可以做細一點,比如類似滾動發(fā)布,每一輪(比如10%)都走藍綠,到下一輪時就回收藍色當綠色。這樣就只需要10%的冗余了。
③ 影子發(fā)布
核心是流量復(fù)制。老版本依然保持服務(wù),新版本部署到新環(huán)境后,把老版本的流量copy到新版本(可以是部分流量),然后驗證新版本的功能。我們做了一輪純粹的技術(shù)重構(gòu)后,對比新老版本結(jié)果是否一致,經(jīng)常這么玩。如果機器資源不太夠,也可以通過代碼開關(guān)進行相關(guān)驗證。
④ A/B測試
很多策略模塊喜歡A/B。其部署可能都在一個集群,只是策略插件有多分,我們通過程序開關(guān)控制不同的用戶走不同策略,然后對比不同策略的效果。A/B可以很復(fù)雜,也可以認為是金絲雀的一種吧。不展開了,還有專門做ToB的A/B系統(tǒng)的單位,可見其復(fù)雜度和價值。
3)CI/CD
聊到DevOps,都會說到這兩個概念。這兩個單詞分別是Continuous Integration和Continuous Delivery的縮寫。其核心是通過一對自動化的工具和流程,使得我們迭代開發(fā)和發(fā)布變得更高效,更有保障。話題有點大,不討論了,附一張圖:
圖6 典型的CI/CD流程
5、設(shè)計開發(fā)
軟件設(shè)計和開發(fā),應(yīng)該是我們最熟悉的了。不過這次咱們從穩(wěn)定性視角再去看一看。很多事情在設(shè)計開發(fā)階段考慮好,才是ROI最高的。
1)設(shè)計
軟件設(shè)計也是個很大的概念。什么是一個好的設(shè)計?估計不會有什么明確的答案。但是一個糟糕的設(shè)計,會導致我們迭代成本越來越高,穩(wěn)定性保障變得異常困難 。前輩大佬們基于自己的實踐經(jīng)驗,概括了一些大家耳熟能詳?shù)脑O(shè)計原則。我們遵循這些原則,不見得能解決所有問題,但是可以規(guī)避很多可能的大坑。
① KISS(Keep It Simple, Stupid)原則
愛因斯坦講過:如果你不能簡單的解釋它,說明你還沒有足夠的理解它。某度的“簡單可依賴”似乎也是在強調(diào)這個事情。只有它足夠“簡單”,它才更“可依賴”的。簡單在軟件工程里意味著:
- 當有故障時,我們可以快速的定位;
- 當重構(gòu)或接手時,我們可以更容易;
- 我們往往都少寫了很多行代碼,無論是開發(fā)效率還是維護成本都會更低;
- 能做出簡單的設(shè)計,意味著我們對這個事情看得更透,實現(xiàn)質(zhì)量更高。
為了簡單我們:
- 要盡量避免引入一些大家不熟知或未被驗證的技術(shù)棧;
- 不需要一些隱晦的實現(xiàn),可能他看起來很cool;
- 不提倡每個工程師都最大化自己的“個性”,需要遵循一些規(guī)范,雖然他看起來很笨重;
- 最重要的是我們一定要始終相信總會有更簡單直接的實現(xiàn)。
② YAGNI(You Ain’t Gonna Need It)原則
意思是,如果一個事情你不是今天就需要,那大概率就是你不需要的。我們總希望自己能高瞻遠矚,一勞永逸,偶爾還想秀一秀技術(shù)。但事實是,我們不管是產(chǎn)品功能,還是代碼實現(xiàn),總是有很多無用或者很少用到的東西(2/8定律)。多余的這部分反而是更容易出錯且維護成本更高的(因為團隊對這部分更陌生,且升級迭代時經(jīng)常忽略這部分)。所以我們要盡量杜絕過度設(shè)計,包括畫蛇添足,過于超前等等。很多時候識別真正現(xiàn)在就需要的東西,還是有點難度的。作者認為,
- 如果無法做到事前判斷,那時候一定要做到時候及時評估。該刪就得大膽刪,因為維護成本往往比開發(fā)成本更高。這個評估過程,也會對我們未來的判斷帶來一些經(jīng)驗和依據(jù);
- 判斷一個事情暫時用不上,那么就看我們現(xiàn)在實現(xiàn)和未來實現(xiàn)成本差異有多大。如果差別不大,或現(xiàn)在做成本小那么一丟丟,那么就放到后面再去實現(xiàn)吧。做好擴展能力設(shè)計等就ok了。
所謂前瞻性設(shè)計,更多是在思考和調(diào)研階段要盡量考慮周全,想好各種異常和未來擴展性需求。而真正實現(xiàn)的時候,做取舍才能體現(xiàn)架構(gòu)師真正的實力。很多時候我們倡導提供簡單直接的實現(xiàn),然后做好兜底。兜底可以很暴力,只要他發(fā)生的頻率不高,很多時候都是可以接受的。等我們無法容忍的時候,就有動力優(yōu)化了。敏捷開發(fā)中有很多這方面的思考:我們持續(xù)交付那些優(yōu)先級高的最小集合。讓系統(tǒng)先跑起來,然后根據(jù)用戶(可能是甲方)實際使用反饋再決策需要增加哪些特性或哪些體驗需要優(yōu)化。
③ DRY(Don’t Repeat Yourself)原則
顧名思義,要以Ctrl C/Ctrl V為恥。我們應(yīng)該盡最大努力杜絕重復(fù)代碼。提高代碼復(fù)用,對于開發(fā)、維護效率至關(guān)重要。更重要的是,我們不該把測試等額外的精力浪費在重復(fù)測試幾乎相同的代碼上。為了減少重復(fù),我們自然會對自己的代碼做更多的分層、抽象、局部重構(gòu)等,使得每段代碼,每個函數(shù)他的職責會越來越明確,單一。
④ SOLID原則
大名鼎鼎,大家應(yīng)該都非常熟悉了。針對面向?qū)ο髨鼍?,大佬?一說是Robert J. Martin,即Uncle Bob首次提出的,應(yīng)該不全是他的)總結(jié)出了五條原則,目的是讓代碼可維護性更高,更好理解,更容易擴展,避免隨著代碼量的增加代碼越來越復(fù)雜。從穩(wěn)定性角度,遵循SOLID原則,也會使得我們的代碼變更更加可控,影響面不會被無限放大。這幾個原則實在太出名了,請各位客觀自行查閱相關(guān)資料吧。附圖如下:
圖7 SOLID原則
⑤ IDEALS原則
分布式系統(tǒng),尤其是微服務(wù)盛行的今天,有人覺得也應(yīng)該有類似SOLID的一些準則,用來指導整體微服務(wù)架構(gòu)設(shè)計和實現(xiàn)。2020年時候,InfoQ上有位大佬提出了IDEALS的概念,目前看影響肯定沒有SOLID那么大,但可以對我們帶來一些啟發(fā)。遵循這些原則,雖然不能解決所有問題,但是可以讓我們的設(shè)計和技術(shù)選型有據(jù)可依,至少不會跑太偏。下面大致解釋下概念:
IDEALS是以下幾個單詞的首字母拼接:Interface segregation, Deployability (is on you), Event-driven, Availability over consistency, Loose coupling, Single responsibility。
- 接口隔離(Interface segregation)
希望通過面向不同的客戶、不同的應(yīng)用場景提供單獨的接口,減少不同客戶之間的改動影響到其他客戶。這里最典型的一個問題是web和移動APP是否要提供獨立的接口?BFF(Backend for Frontends)就是非常典型的一個設(shè)計模式,可以自行了解下。
- 可部署性(Deployability (is on you))
中文翻譯不一定準確,僅供參考。微服務(wù)架構(gòu)使得線上部署單元變多了,所以如何更高效的發(fā)布和監(jiān)控變得更加重要。這里好的工具對效率的提升至關(guān)重要。下面幾類技術(shù)和工具,興許都能用得上:容器化(Docker+k8s)、Service Mesh(Istio含Envoy)、API Gateway(提供協(xié)議轉(zhuǎn)換、接口路由、安全控制、熔斷、限流、配額管理、流量監(jiān)控等等能力,部分能力逐漸在被Service Mesh和開發(fā)框架,如Spring Cloud等代替。Kong/tyk),Serverless(各云廠商提供的云函數(shù)FaaS),監(jiān)控工具(Prometheus/Grafana,還可以關(guān)注laiwei老師的Open Falcon和最新的Nightingale),日志采集(其實很多監(jiān)控方案都自帶了采集能力,ELK/splunk),鏈路追蹤(Zipkin/Jaeger),DevOps(文化+工具+實踐),灰度發(fā)布,IaC(Infrastructure as Code),CI/CD(Jenkins/Argo CD/Flux)。如果你有個非常靠譜的基礎(chǔ)架構(gòu)或運維團隊,那么以上其實更多是關(guān)注如何使用就好了。如果沒有或你就是那個團隊成員,恭喜你,在微服務(wù)和云原生的沖擊下,這塊更新?lián)Q代還是比較快的,要學習掌握的真不少。關(guān)鍵這些都是一些基礎(chǔ)設(shè)施,對穩(wěn)定性和易用性要求都極高。
- 事件驅(qū)動(Event-Driven)
雖然他不等價于異步模式,但他們密不可分。微服務(wù)架構(gòu)中,鼓勵大家大量使用基于消息的異步通信。這是調(diào)用方和服務(wù)提供方之間比較徹底的解耦方式。一方面,可以做到消峰,高并發(fā)情況下,也不會因為下游服務(wù)處理能力導致拒絕服務(wù);另一方面,消費方可以根據(jù)消息量靈活擴縮容,而且還給你留了一定的反應(yīng)時間。目前MQ中間件基本都已經(jīng)很成熟了,一般場景下甚至丟消息都不用太考慮,只有增加一些兜底措施就好。另外,MQ的可用性一般都遠高于業(yè)務(wù)服務(wù),所以也不用擔心引入他帶來的穩(wěn)定性損失。只要對于響應(yīng)時間沒有特別敏感,原則上能異步就異步。挑戰(zhàn)可能是對于業(yè)務(wù)本身的事件驅(qū)動的抽象,前端的體驗設(shè)計和MQ本身的規(guī)劃和管理上吧。
- 可用性勝過一致性(Availability over Consistency)
在大部分互聯(lián)網(wǎng)場景下,我們更注重可用性,而對于一致性,降級為了追求最終一致性。CAP原理相信大家都非常熟悉了,而且這個話題有點大。這里就當做是一種常識吧。Command Query Responsibility Segregation (CQRS) 可以了解下,附一張原圖:
圖8 CQRS
- 松耦合(Loose-Coupling)
解耦帶來的好處應(yīng)該不用解釋了。具體解耦方式也有多種。這里核心不是怎么解,而是怎么發(fā)現(xiàn)。比如一個模塊本來很簡單,后來由兩個團隊共同維護,那可能這兩個團隊分工合作就有耦合了,可以考慮拆分。如果一個系統(tǒng)足夠簡單,數(shù)據(jù)量也不大,非得搞個CQRS,全異步那也只是在徒增煩惱,不見得能真的體會到“解耦”的好處。
- 單一職責(Single Responsibility)
類似SOLID里的S,他強調(diào)的是服務(wù)內(nèi)部要高內(nèi)聚。很容易理解,但是可能很難把握。服務(wù)分的太粗,就逐漸退化成單體應(yīng)用了。如果拆的特別細碎,部署運維會是個問題,另外還會額外增加一些RPC代價。個人一些簡單原則(只要糾結(jié),肯定都能找到一個反例,僅供參考):
- 一個微服務(wù),盡量對應(yīng)一個數(shù)據(jù)庫。這里,如果某種場景必須要有事務(wù)保證,那相關(guān)操作必然得在一個服務(wù)。不過建議盡量減少大事務(wù),而是追求最終一致性,上面有討論;
- 如果業(yè)務(wù)場景中,絕大部分請求,都會涉及多個同一層“模塊”(分層是另一個維度,不算),那這些“模塊”就放到一個服務(wù)吧,除非有很強的拆開的理由。這里如果用DDD描述可能更容易理解。不過作者對DDD理解不夠深入,不敢提;
- 組織架構(gòu)決定系統(tǒng)架構(gòu),不同團隊維護的,就想辦法從代碼層面拆清楚;
- 如果拆開目前沒有引入無法接受的成本,那么就先拆開吧。合并,一般都會比拆分成本更小。
- 拆分過程可能比結(jié)果更重要。能把一個看起來凌亂的事情抽象成多個相對獨立的事務(wù)的組合,必然會降低其復(fù)雜度。如果考慮運維成本等,可以先只是邏輯拆分,物理上可以是一個包,一個節(jié)點。
2)開發(fā)
開發(fā)過程其實真正寫碼的時間也很少,這里強調(diào)的更多是一些局部設(shè)計和編碼過程中要避免的一些坑。當然我們編寫出來的代碼質(zhì)量才是最終決定系統(tǒng)運行情況的根本保障。各大廠應(yīng)該都會有一些開發(fā)手冊等。其中最出名的應(yīng)該是《阿里巴巴java開發(fā)手冊》了,作者認為沒有之一。手冊中自稱愿景是“碼出高效,碼出質(zhì)量”。很顯然通過此類手冊,我們希望一方面能規(guī)范一些開發(fā)過程,另外,也通過一些基礎(chǔ)的保障和警示,提高程序員編碼質(zhì)量。其中每一條規(guī)約后面,可能都深藏著無數(shù)深坑和歷史上在此坑掉下去的大俠們。
我們也可以從穩(wěn)定性角度制定類似規(guī)范。我們要做的是不斷完善自己的開發(fā)規(guī)范同時,應(yīng)該根據(jù)團隊實際遇到的一些問題,復(fù)盤的線上事故等來不斷沉淀自己團隊的一些相應(yīng)的規(guī)范和禁忌。線上事故是我們繳的最貴的學費,不要輕易浪費他。
有規(guī)范是一方面,更重要的是執(zhí)行。這塊可能更多是依賴一線leader的執(zhí)行力和管理能力了。
6、工具&文化
這倆放一起,其實沒那么生硬。有一種文化叫“工具文化”~
1)工具
其實前面聊了很多工具相關(guān)的事情了。這些工具包括一些開源項目或商業(yè)軟件,也可能是團隊自研小工具等等。我們經(jīng)常講能依靠工具就不要依賴流程,能建立流程就不要依賴人的主動性。合理使用工具,讓一切能自動化的自動化,一方面是提高執(zhí)行效率,另一方面降低人為引入的失誤風險。一些常規(guī),繁瑣或容易出錯的事情,我們就應(yīng)該考慮建設(shè)相對應(yīng)的工具。比如一些環(huán)境搭建,代碼檢查,自動化測試和CI/CD流程等都可以完全交給工具去完成。除此之外,線上trace,debug,兜底操作等都依賴工具支持。還可以例舉很多場景。
作為一名優(yōu)秀的工程師,咱們能自己動手提升自身工作效率,降低犯錯的概率,為什么不多去努力呢?
相反,如果工具層面欠缺太多,那就該咬咬牙把這塊能力先補上吧。比如,日志采集和監(jiān)控,CI/CD,如果沒有很好的工具支撐,那我們就需要(反復(fù)地)做很多額外的事情,而且隨著系統(tǒng)演進和團隊壯大,這部分工作量都是成倍的增長的。我們就該盡早重視這部分建設(shè)。一些小團隊創(chuàng)業(yè)型團隊,這部分反而往往被忽略,不被重視。看起來組織永遠沒人力投入,實際上過段時間去統(tǒng)計,你就會發(fā)現(xiàn)總的額外投入往往要比工具本身上的投入要大好多倍。
穩(wěn)定性建設(shè)是個無底洞,如果沒有很好地提效工具,那么ROI就會越來越低。如果你想說服你老板加大在穩(wěn)定性方面的投入,那不得不去講ROI。工具雖然不是全部提效手段,但肯定是最重要的一個。
2)文化
我們通篇都在講穩(wěn)定性可以怎么怎么保障,看似很系統(tǒng)。實際情況是,很多時候所謂穩(wěn)定性建設(shè)可能都只是有一陣風,吹過之后似乎什么也沒留下。系統(tǒng)在不斷迭代,人員也會不停流動,如果沒有一個好的文化傳承,我們其實無法保證這塊的持續(xù)投入和效果。那怎么建設(shè)一個團隊的穩(wěn)定性文化呢?其實這話題可能是我一萬個最不擅長的事情之一了。不過既然提出來了,就簡單分享下此刻的一些認知吧。參考HR部門關(guān)于企業(yè)文化建設(shè)的思路:
首先,提煉它。文化一般都希望能提煉成一兩句話,讓團隊朗朗上口。這樣才能更好的傳播和傳承。我自己團隊,用一句話強調(diào)穩(wěn)定性的重要性:穩(wěn)定性是我們的底線。意思是,如果穩(wěn)定性沒有做好,做再多拔高的事情,其實也都可能會歸零。我們不要求一切都以穩(wěn)定性為前提(很多時候迭代壓力會極端的大),但是要明確意識到,穩(wěn)定性不管什么時候都是我們的底線,要時刻提醒自己是不是做的足夠好了。至少要做到在當時那個環(huán)境下充分評估穩(wěn)定性風險,并保證最大程度的投入。如果因為一些交付時間等原因,做了一些妥協(xié),那一定要在接下來最快的時間內(nèi)把穩(wěn)定性欠債還上。
其次,運營好。文化是需要運營的。作者認為比較實用的一些運營方式有:
1)建立明確的獎懲措施。比如線上事故得有些具體懲罰措施??梢允俏镔|(zhì)的,也可能是更柔和的。當然做得好的,要多去鼓勵,多去傳播。
2)識別關(guān)鍵人員,并加以引導。讓更多的人幫助自己推廣相關(guān)理念和要求。比如每個小組的leader,一些核心開發(fā)人員。他們在一線,很多時候他們說的話更有感染力。所以一定要先跟這些人員達成一致,并讓他們一方面身體力行;另一方面,作為穩(wěn)定性文化的堅定傳播者,幫助組織共同傳承和發(fā)揚光大。
3)洗腦式宣貫。我們要不停的講一些穩(wěn)定性方面的意識和實操層面要關(guān)注的事情(比如監(jiān)控設(shè)計和發(fā)布設(shè)計都是系統(tǒng)設(shè)計階段要考慮的)。穩(wěn)定性宣貫有個特別好的時機,那就是線上出故障時,我們一般都會組織復(fù)盤或case study。那這時候所有的穩(wěn)定性主張都可以重新再review下??次覀兡睦镒龅煤茫男c沒做到位。只要堅持高質(zhì)量的復(fù)盤和case study,就可以在團隊內(nèi)部不斷強化相關(guān)意識。而且問題越多,力度越大。問題不多時候有稍微放一放不見得一定是壞事。當然系統(tǒng)不可能沒有問題的,這個度就得管理者自己拿捏了。小道cr問題,qa發(fā)現(xiàn)的bug等等只要想強調(diào),就可以組織case study。這里復(fù)盤再稍微羅嗦下的是:一方面,復(fù)盤時不一定都是全員可以參加,所以復(fù)盤結(jié)論的通曬就很重要了(不要藏著掖著);另一方面,復(fù)盤容易,閉環(huán)往往都不是很理想,所以應(yīng)該更多的去關(guān)注閉環(huán)效果。其中就可以review下文化,意識層面的改進項。
再者,把它融入到其他文化建設(shè)中,形成更廣泛的傳播。穩(wěn)定性文化單獨拿出來,其實有可能只是一個點。但是像工程師文化,新人融(xi)入(nao),這些都是我們經(jīng)常會去講,會去做的。那么作為喜歡追求極致的工程師們,能夠容忍自己開發(fā)的系統(tǒng)有缺陷嗎?至少應(yīng)該以此為恥吧?新入職培訓和熟悉業(yè)務(wù)階段,是否可以專門設(shè)置相關(guān)課程?作為一個新人,至少應(yīng)該看一看組織歷史上都犯過哪些錯誤吧?不斷沉淀一些相關(guān)案例,讓成員們定期多去關(guān)注這些案例。自然就可以從中吸取一些教訓,尤其哪些重復(fù)犯的錯誤,都應(yīng)該被深深地記住。
寫在后面
穩(wěn)定性建設(shè)至關(guān)重要。
服務(wù)穩(wěn)定性對于公司口碑,甚至是對其直接的商業(yè)利益都有重大影響。歷史上血淋淋的宕機事件、安全事故比比皆是。不知這背后又有多少猿類內(nèi)心和肉體上留下了揮之不去的烙印。
穩(wěn)定性建設(shè),對于系統(tǒng)設(shè)計,團隊協(xié)同效率,程序員自身修養(yǎng)都提出了更高的要求。所以只要堅持投入,對于系統(tǒng)穩(wěn)定性提升,團隊整體戰(zhàn)斗力提升和成員個人成長都是大有裨益的。
穩(wěn)定性建設(shè)不好做,需要耐心。
1)穩(wěn)定性建設(shè)很多時候都是在做保底線的事情。這就意味著,不出問題甲方(用戶、老板、合作伙伴)基本沒有人能感受到。他們關(guān)注到你的時候,大概率線上已經(jīng)出了事故。所以,想得到大家的欣賞還是挺難的,如果想長期從事相關(guān)工作,得做好吃土的準備。不過一般很少有人專門做穩(wěn)定性建設(shè),更多是在自己開發(fā)交付過程中不斷完善系統(tǒng),使其更讓人放心。
2)穩(wěn)定性建設(shè)投入總是沒保障。我們總是(尤其是在業(yè)務(wù)初期)著急的開發(fā)著新的特性,迭代效率基本就是個無法妥協(xié)的事情。如果不咬牙堅持,付出額外的努力,根本就沒法堅持。
3)穩(wěn)定性建設(shè)涉及軟件開發(fā)整個生命周期。想每個環(huán)節(jié)同時都做到理想狀態(tài)幾乎不可能。所以也意味著他是個慢功夫,甚至剛開始時候很容易犯左傾冒進主義錯誤,后期又無法堅持長期斗爭。從上到下得有耐心才可能做得更好。