系統(tǒng)壞了,慌不慌
本文轉(zhuǎn)載自微信公眾號(hào)「跨界架構(gòu)師」,作者Zachary 。轉(zhuǎn)載本文請(qǐng)聯(lián)系跨界架構(gòu)師公眾號(hào)。
作為程序員,相信有一件事是大家最不想見(jiàn)到的。那就是,線上運(yùn)行的系統(tǒng)出現(xiàn)了技術(shù)性故障。(特別還是周末你正在外面happy的時(shí)候:D)
處理這類(lèi)事情特別能體現(xiàn)一個(gè)人的綜合能力。因?yàn)樗鼤?huì)涉及到抗壓能力、對(duì)外的溝通能力,以及排查問(wèn)題所需的技術(shù)能力等等多個(gè)方面。
如果你還沒(méi)機(jī)會(huì)成為核心開(kāi)發(fā),其實(shí)很少會(huì)有這樣充滿壓力的經(jīng)歷。因?yàn)樵谶@個(gè)情況下處理事情其實(shí)是很慌的,畢竟所有使用系統(tǒng)的人以及他們的老板、你的上級(jí)、你的老板等等無(wú)數(shù)雙眼睛都在盯著這件事情。
我還記得有一年雙11,我作為“首席問(wèn)題處理官”正在緊急處理服務(wù)器扛不住壓力的問(wèn)題,老板默默走到我身后問(wèn)到“什么問(wèn)題啊?什么時(shí)候好?”。你腦補(bǔ)一下這畫(huà)面,想象一下看看。
只要你接下去還會(huì)繼續(xù)從事程序員這個(gè)職業(yè),我想這樣的場(chǎng)景你總歸會(huì)有機(jī)會(huì)遇到的。因?yàn)橐粋€(gè)著名的定律——墨菲定律。
墨菲定律:凡是可能出錯(cuò)的事就一定會(huì)出錯(cuò)。維基百科
如果沒(méi)有一個(gè)清晰的應(yīng)對(duì)思路,那么一旦發(fā)生線上問(wèn)題就會(huì)像熱鍋上的螞蟻一樣,急得團(tuán)團(tuán)轉(zhuǎn),像無(wú)頭蒼蠅一樣到處亂撞(試)。
所以,我這次就想分享一些我多年作為“首席問(wèn)題處理官”所總結(jié)下來(lái)的經(jīng)驗(yàn)。這可是承載了我N多汗水和腦細(xì)胞的經(jīng)驗(yàn)~
在日常的項(xiàng)目開(kāi)發(fā)迭代過(guò)程中我們遇到一個(gè)bug,大家的處理過(guò)程幾乎是一樣的:定位bug -> 解決bug??赡苌俨糠秩嗽诮鉀Qbug之后會(huì)有一個(gè)思考、復(fù)盤(pán),看看是否有類(lèi)似bug的地方,一并處理掉。
這個(gè)“定位 -> 解決 -> 復(fù)盤(pán)”的過(guò)程也同樣適用于線上問(wèn)題的處理。但是必然不僅僅如此。
俗話說(shuō),解決一個(gè)問(wèn)題最難的地方不是解決的過(guò)程,而是定位的過(guò)程。所以,針對(duì)線上問(wèn)題我們等不起定位問(wèn)題所花費(fèi)的時(shí)間,因此要將「恢復(fù)」系統(tǒng)正常使用放在最首要的位置。所以,這個(gè)過(guò)程就變成了:“恢復(fù) -> 定位 -> 解決 -> 復(fù)盤(pán)”。
這里多說(shuō)一句,有一部分人的觀點(diǎn)認(rèn)為,將恢復(fù)系統(tǒng)作為首要目標(biāo),應(yīng)當(dāng)包括犧牲保留現(xiàn)場(chǎng)的動(dòng)作,因?yàn)檫@個(gè)動(dòng)作可能也需要耗費(fèi)數(shù)分鐘才行。
我對(duì)這個(gè)觀點(diǎn)持反對(duì)意見(jiàn)。理由是,解決問(wèn)題的時(shí)長(zhǎng)的確是一個(gè)很重要的指標(biāo),但是問(wèn)題既然已經(jīng)發(fā)生,如果由于沒(méi)有保留現(xiàn)場(chǎng)導(dǎo)致后續(xù)沒(méi)有排查到根源,導(dǎo)致下次該問(wèn)題再次出現(xiàn),到時(shí)候場(chǎng)面將會(huì)更加難看。所以我對(duì)這事的觀點(diǎn)是,保留現(xiàn)場(chǎng)最重要。因此,這個(gè)過(guò)程又變成了:“保留現(xiàn)場(chǎng) -> 恢復(fù) -> 定位 -> 解決 -> 復(fù)盤(pán)”。
當(dāng)然了,保留現(xiàn)場(chǎng)也不是說(shuō)非得面面俱到,花很多時(shí)間。用最快的方式保留你當(dāng)下所能想到的所有相關(guān)線索的地方即可。如果事后還是由于線索不足導(dǎo)致未能排查到根本原因,那只能說(shuō)經(jīng)驗(yàn)不足,考慮一下以后需要多保留哪些現(xiàn)場(chǎng)數(shù)據(jù)才行。
好了,確定了這5個(gè)步驟,那么具體每個(gè)步驟可以做些什么呢?我來(lái)一個(gè)個(gè)說(shuō)。
/01 保留現(xiàn)場(chǎng)/
保留現(xiàn)場(chǎng)最最最重要的一件事是保存異常程序的dump文件。有了它,你就可以擺脫盲人摸象式的分析問(wèn)題,可以快速定位問(wèn)題的發(fā)源地。
我用了三個(gè)“最”來(lái)強(qiáng)調(diào)它的重要性。如果你還沒(méi)掌握它,那么后面我提到的東西都先放一放,先去掌握它。
另外,如果系統(tǒng)的監(jiān)控體系并不完備的話,還需要將問(wèn)題發(fā)生時(shí),操作系統(tǒng)、各第三方組件自帶的監(jiān)控?cái)?shù)據(jù)快速地通過(guò)截圖保存下來(lái)。
保存監(jiān)控?cái)?shù)據(jù)的時(shí)候要特別留意一下網(wǎng)絡(luò)相關(guān)的數(shù)據(jù)。如果發(fā)現(xiàn)網(wǎng)絡(luò)相關(guān)的數(shù)據(jù)有異常,那么再把當(dāng)下的網(wǎng)絡(luò)連接情況通過(guò)命令保存下來(lái)。因?yàn)橄鄬?duì)來(lái)說(shuō),網(wǎng)絡(luò)出現(xiàn)問(wèn)題的概率遠(yuǎn)遠(yuǎn)大于硬件,不管是程序?qū)е碌倪€是其他原因。規(guī)模越大的系統(tǒng),越是如此。
/02 恢復(fù)/
恢復(fù)系統(tǒng)訪問(wèn)有很多方法。首先不得不提到一個(gè)適用于80%情況的神技了——重啟。沒(méi)錯(cuò),根據(jù)多年的經(jīng)驗(yàn)來(lái)看這招的確在大多數(shù)情況下很有效。
也正因?yàn)閷以嚥凰?,所以很多人?xí)慣性地會(huì)在第一時(shí)間去重啟,導(dǎo)致現(xiàn)場(chǎng)忘記保存并受到破壞。
重啟也分兩種,強(qiáng)制重啟和自然重啟。當(dāng)然優(yōu)先考慮自然重啟,這樣能避免產(chǎn)生一些意料之外的臟數(shù)據(jù)。但是如果是系統(tǒng)出現(xiàn)資源耗用異常的話,就不要傻傻地等自然重啟了,只能強(qiáng)制重啟(kill掉進(jìn)程)。
第二種常見(jiàn)的方法是「回滾」。當(dāng)然它的前提條件是你判斷下來(lái)問(wèn)題的出現(xiàn)是由于最近一次發(fā)布。否則盲目的回滾不但起不到作用,還會(huì)越弄越亂,特別在分布式系統(tǒng)中。因?yàn)樵诜植际较到y(tǒng)中,一旦上下游耦合的地方出現(xiàn)對(duì)接不上,輕則報(bào)錯(cuò),重則出現(xiàn)大量的異常數(shù)據(jù),夠你后續(xù)折騰好久的。
第三種方法是「降級(jí)」。暫停出問(wèn)題的模塊,停止服務(wù)。當(dāng)然,這個(gè)動(dòng)作需要和業(yè)務(wù)方做好溝通,是否單獨(dú)降級(jí)某個(gè)模塊會(huì)導(dǎo)致業(yè)務(wù)不完整之類(lèi)的問(wèn)題。
第四種方法是「限流」或者「擴(kuò)容」。如果你發(fā)現(xiàn)是系統(tǒng)扛不住突增的流量,如果有條件的話可以快速擴(kuò)容幾臺(tái)機(jī)器和程序。如果沒(méi)法擴(kuò)容的話可以選擇限流,將一定百分比的請(qǐng)求直接拒絕服務(wù)。畢竟所有無(wú)法提供服務(wù)和部分無(wú)法提供服務(wù)相比,肯定還是后者劃算。
還有一些比較小眾的方法是「切到備機(jī)」、「故障隔離」等,這里就不展開(kāi)了。它們對(duì)環(huán)境、條件的要求更多一些。
有時(shí)候可能系統(tǒng)并未恢復(fù)到完全正常的狀態(tài),比如,讀取數(shù)據(jù)是OK了,但是某些操作寫(xiě)入數(shù)據(jù)到時(shí)候還是有問(wèn)題。在這樣的情況下,不要著急定位問(wèn)題,還是先盡最大努力恢復(fù)到最大程度的可用狀態(tài)再進(jìn)行下一步的動(dòng)作,畢竟用戶第一嘛。
/03 定位/
關(guān)于定位問(wèn)題,如果有dump文件的話最方便了,通過(guò)dump文件分析工具來(lái)分析dump文件就可以快速定位到出問(wèn)題的代碼行,特別是程序阻塞、內(nèi)存溢出、cpu100%之類(lèi)明顯是程序本身的問(wèn)題。
不同的語(yǔ)言有不同的dump分析工具,可以自行網(wǎng)上搜一下教程。最終目的就是定位到異常點(diǎn)的堆棧信息,有了它就相當(dāng)于直接把問(wèn)題代碼出現(xiàn)在哪里都給定位到了。
如果說(shuō)分析dump文件是跳過(guò)抽絲剝繭的步驟,直擊要害的話。通過(guò)監(jiān)控?cái)?shù)據(jù)、日志層層分析是個(gè)慢活。但是如果缺失dump文件或者從dump文件從未能分析出問(wèn)題的情況下,也只能選擇后者。
我們?cè)诳慈罩尽⒈O(jiān)控?cái)?shù)據(jù)的時(shí)候一定要有關(guān)聯(lián)起來(lái)看的意識(shí),而不能僅僅在單個(gè)維度上看。因?yàn)橛袝r(shí)候你在單個(gè)維度上看到的數(shù)據(jù)像是正常的,但是你關(guān)聯(lián)起來(lái)看就不一定了。比如,tcp連接數(shù)降低了一半,但是內(nèi)存反而漲了100%,為什么?這里面可能就藏著故障的線索。
/04 解決/
定位到了問(wèn)題,解決起來(lái)就很簡(jiǎn)單了。該改代碼的改代碼,該改配置的改配置文件。這里就不多說(shuō)了,畢竟情況太多,大家遇到的可能都不太一樣。
/05 復(fù)盤(pán)/
大家都知道復(fù)盤(pán)的好處,但是真正做復(fù)盤(pán)的人真不多。如果你不知道從何下手來(lái)做復(fù)盤(pán)的話,不妨從以下幾個(gè)問(wèn)題入手,
- 這次故障原因是什么?
- 是否有更快的方式在當(dāng)時(shí)來(lái)恢復(fù)業(yè)務(wù)?
- 如何避免再出類(lèi)似故障?
- 當(dāng)前系統(tǒng)中是否還有類(lèi)似的潛在風(fēng)險(xiǎn)?
如果你能回答這些問(wèn)題,我覺(jué)得這個(gè)復(fù)盤(pán)就很到位了,剩下的就是執(zhí)行。
當(dāng)然了,不管如何優(yōu)秀的處理故障,最理想的還是不要發(fā)生故障。所以我們需要在前期做更多的準(zhǔn)備。
/01 了解你的程序/
我們很多人了解自己負(fù)責(zé)的程序只有通過(guò)coding這一種途徑。除非該程序是個(gè)單體應(yīng)用,否則這樣的方式是遠(yuǎn)遠(yuǎn)不夠的。
我建議你按照以下清單去了解你的程序:
- 程序包含有哪些模塊,對(duì)應(yīng)使用者是哪些?哪些是核心模塊,哪些是可以“棄車(chē)保帥”的?
- 多個(gè)模塊/系統(tǒng)間如何流轉(zhuǎn)的?(盡量畫(huà)一個(gè)流程圖,加深記憶)
- 依賴了哪些中間件,誰(shuí)負(fù)責(zé)維護(hù)他們?
- 依賴了哪些其他的程序,強(qiáng)依賴還是弱依賴,誰(shuí)負(fù)責(zé)維護(hù)他們?
- 依賴的存儲(chǔ)、消息隊(duì)列背后又依賴了哪些存儲(chǔ),存儲(chǔ)運(yùn)維負(fù)責(zé)人是誰(shuí)?
- 線上的程序部署在什么環(huán)境。你是否有條件獨(dú)立進(jìn)行部署并調(diào)優(yōu)?
/02 做好監(jiān)控/
大多數(shù)的故障不是突然發(fā)生,而是有一個(gè)逐漸積累的過(guò)程,直到爆發(fā)。所以監(jiān)控的價(jià)值不僅僅是看看數(shù)據(jù)那么簡(jiǎn)單,對(duì)于異常識(shí)別特別有幫助。
一般監(jiān)控分兩個(gè)維度,系統(tǒng)維度和業(yè)務(wù)維度。監(jiān)控指標(biāo)分為三層,「環(huán)境指標(biāo)」、「程序指標(biāo)」、「業(yè)務(wù)指標(biāo)」。具體怎么做我在之前的文章《分布式系統(tǒng)關(guān)注點(diǎn)——360°的全方位監(jiān)控》有具體說(shuō)明,這里就不贅述了。
如果是分布式系統(tǒng),還可以搭建一個(gè)請(qǐng)求鏈路跟蹤系統(tǒng)。有很多成熟的現(xiàn)成解決方案,CAT、SkyWalking、Zipkin、Pinpoint等等。
多說(shuō)一句,我們?cè)谧霰O(jiān)控預(yù)警的時(shí)候,除了設(shè)置閾值還要關(guān)注一下波動(dòng)率。比如,某項(xiàng)資源日常使用率20%,除了設(shè)置超過(guò)80%的閾值進(jìn)行預(yù)警之外,在它產(chǎn)生波動(dòng)幅度100%(使用率40%)以上的時(shí)候也需要預(yù)警,提前讓人關(guān)注。否則一旦以一個(gè)較快的速度增長(zhǎng)到80%之后,留給你在故障爆發(fā)前消滅它的機(jī)會(huì)就非常渺茫了。
另外,針對(duì)常見(jiàn)的故障預(yù)設(shè)幾套故障響應(yīng)方案,以及進(jìn)行定期的故障演練(一般上了一定規(guī)模的公司或者處于擴(kuò)張期的公司才會(huì)考慮)可以讓團(tuán)隊(duì)面對(duì)線上故障的時(shí)候更加地游刃有余。
假如你不幸成為了線上故障的解決者,如果上級(jí)不在旁邊的話,需要定時(shí)向上級(jí)匯報(bào)問(wèn)題處理情況,以便TA了解問(wèn)題的嚴(yán)重程度、修復(fù)進(jìn)度并作出決策。
反正就算你不上報(bào),遲早也會(huì)被催。與其被動(dòng)的被催,不如主動(dòng)上報(bào)。
好了,總結(jié)一下。
這篇呢Z哥和你分享了一些處理線上故障的經(jīng)驗(yàn)。
從思路上,分為五個(gè)步驟“保留現(xiàn)場(chǎng) -> 恢復(fù) -> 定位 -> 解決 -> 復(fù)盤(pán)”。除了第四步「解決」外,我都進(jìn)行了展開(kāi)。
- 保留現(xiàn)場(chǎng)。主要是保存dump文件,以及截圖系統(tǒng)監(jiān)控的數(shù)據(jù)(沒(méi)有在外部搭建的監(jiān)控系統(tǒng)內(nèi)的部分)。
- 恢復(fù)。主要重啟、回滾、降級(jí)、限流和擴(kuò)容。還有一些小眾的方法「切到備機(jī)」、「故障隔離」等
- 定位。分析dump文件、分析監(jiān)控?cái)?shù)據(jù)、程序運(yùn)行日志。
- 解決。
- 復(fù)盤(pán)。搞清楚以下4個(gè)問(wèn)題就夠了:
- 這次故障原因是什么?
- 是否有更快的方式在當(dāng)時(shí)來(lái)恢復(fù)業(yè)務(wù)?
- 如何避免再出類(lèi)似故障?
- 當(dāng)前系統(tǒng)中是否還有類(lèi)似的潛在風(fēng)險(xiǎn)?
然后還建議了你要未雨綢繆,盡可能減少故障在線上爆發(fā)。
- 解你的程序
- 做好監(jiān)控