
圖片來(lái)自網(wǎng)絡(luò )/侵刪
本文最初發(fā)布于 Itamar Lechowicer 博客,經(jīng)原作者授權由 InfoQ 中文站翻譯并分享
概 述
我們公司運維著(zhù) 15 個(gè) Web 應用,主要的工作就是按需交付基于數據驅動(dòng)的 Web 應用程序,用于支撐實(shí)時(shí)決策的制定。
這些應用的預期是在高負載下依然保持高可用。其中的主 Web 應用是一個(gè)歷史遺留的大型多服務(wù)系統。系統中的大部分服務(wù)都有超過(guò) 15 年的歷史并且經(jīng)過(guò)了好幾代人的重構。試想一下,負責編寫(xiě)系統代碼的人現在可能已經(jīng)離職或已經(jīng)調整到其他崗位了。
過(guò)去幾年我們團隊的主要目標是就是針對這些服務(wù)進(jìn)行性能優(yōu)化。本次我將和你分享在性能優(yōu)化的過(guò)程中,我們的一些主要經(jīng)驗總結和當時(shí)決定這么做的原因。
認知改變時(shí)刻
在某次事件中,用戶(hù)增加了對我們應用的使用率,導致我們應用的數據流量大幅增加。在此事件過(guò)程中,用戶(hù)抱怨我們的應用性能實(shí)在太差,以至于無(wú)法在應用上完成全套的業(yè)務(wù)流程。為此,我們開(kāi)始利用監控工具分析應用的性能瓶頸。通過(guò)應用監控工具,我們發(fā)現服務(wù)在獲取 DB 連接上消耗了 90% 的響應時(shí)間。
但是 DB 看上去一切正常,所以,我們開(kāi)始分析應用的 DB 連接池。分析發(fā)現,所有的 pod 將連接池中全部可用的連接都使用了。因此我們猜測服務(wù)在關(guān)閉連接上可能有問(wèn)題。于是,我們花了幾個(gè)小時(shí)時(shí)間檢查代碼,嘗試找到連接沒(méi)有被釋放的地方。最終,我們的一個(gè) TeamLeader 發(fā)現,pod 的存活探針在做一次簡(jiǎn)單的 DB 心跳請求之后沒(méi)有釋放 DB 連接。隨后,我們立即在 pod 存活探針的請求中增加了一行用于釋放 DB 連接的代碼。影響是可怕的。眨眼間,應用的性能就開(kāi)始穩定下來(lái)并且用戶(hù)也恢復了正常使用。
就在此次事件的前一天,我們才執行過(guò)一次負載測試,以確保應用程序能夠承受預期的使用量增長(cháng),測試結果表明應用的性能是在正常范圍內的。然而事實(shí)證明這個(gè)測試結論是錯誤的,錯誤的測試結論誤導我們以為應用程序沒(méi)有需要修復的問(wèn)題。我們深刻認識到了錯誤,我們需要做得更好。以下是我們在此次事件中學(xué)習到的一些經(jīng)驗和總結。
總結一:不要使用平均等待時(shí)長(cháng)作為衡量服務(wù)負載的指標——核查應用的“尾部”值
當用戶(hù)抱怨應用響應慢的時(shí)候,我們發(fā)現平均等待時(shí)長(cháng)指標并沒(méi)有明顯的變化。當我們回顧了這些指標數據的時(shí)候,注意到了一些有趣的事情:之前我們是將平均請求時(shí)間作為服務(wù)等待的主要指標,因此,這次我們將 90% 請求等待時(shí)長(cháng)的數據做了一個(gè)圖表,看看這個(gè)圖表能不能反饋些信息。果不其然,在用戶(hù)抱怨應用慢的時(shí)候,我們觀(guān)察到圖表中等待時(shí)長(cháng)急劇增加。平均等待時(shí)長(cháng)指標之所以沒(méi)有明顯變化,是因為太多的快速請求將平均值拉下來(lái)了。所以我的建議是,不使用平均等待時(shí)長(cháng),而使用 50%,90%,95%,99% 的平均等待時(shí)長(cháng)作為服務(wù)響應的指標。核查那些遠遠超過(guò)正常值范圍的“尾部”值是非常重要的。
總結二:在性能優(yōu)化上投入時(shí)間、工具和人力
要保持應用的高性能,我們必須具備以下條件:
負載測試和負載場(chǎng)景——具備可用的負載測試和負載場(chǎng)景非常重要。
應用監控工具(APM)——諸如 Dyanatrace,AppDynamics 和 Epsagon 等工具。APM 在監控服務(wù)上可以幫我們節約大量的時(shí)間。因此在生產(chǎn)環(huán)境安裝至少一個(gè) APM 是非常有必要的。
有效的日志——有效的日志是生產(chǎn)服務(wù)中斷調查和性能問(wèn)題調查的基本條件。因此你必須確保應用的日志是清晰且有用的。
日志分析工具——你不能從很多文件中讀取和搜索日志,尤其當你的服務(wù)是集群的時(shí)候,通過(guò)文件讀取日志將變得更加困難。因此,花時(shí)間投產(chǎn)一個(gè)諸如 ELK,Grafana 或 Splunk 的日志收集器和分析工具是非常有必要的。
專(zhuān)業(yè)的人力支撐——對于上面提到的知識或者工具,如果你的團隊沒(méi)有相關(guān)的專(zhuān)業(yè)人才,那么你將什么也干不了。
因此,針對復雜的系統,我建議投入專(zhuān)門(mén)的人和時(shí)間來(lái)處理。(例如,SRE 團隊就能很好的勝任此項工作)
總結三:老系統將會(huì )消亡(除非我們激活它們)
作為人類(lèi),我們都有創(chuàng )造新事物的沖動(dòng)和欲望,并且對創(chuàng )造出來(lái)的產(chǎn)品有一種所有權感。在軟件的世界里,在我們需要處理的矛盾中,有時(shí)候也會(huì )包含這樣的矛盾。一方面,有一個(gè)老系統需要我們維護;而另一方面,有一個(gè)炫酷的新系統我們想要去開(kāi)發(fā)。那么這個(gè)時(shí)候,我們就需要決定將時(shí)間投入到那塊。當我們面對這樣的矛盾時(shí),我們必須記住,如果我們不繼續在老系統上進(jìn)行開(kāi)發(fā)和添加新功能,那么對老系統的了解會(huì )隨著(zhù)時(shí)間的推移而消失。因此,當我們面對系統故障或客戶(hù)新需求時(shí),由于缺少對老系統的了解或者能力問(wèn)題,將無(wú)法達成目標。換句話(huà)說(shuō),當我們失去對于老系統的了解之后,系統的 MTTR(平均修復時(shí)間) 上升了。
因此,我的建議是,要時(shí)??酥葡胍獎?chuàng )造一個(gè)新的、炫酷事物的沖動(dòng),將時(shí)間投入到對老維護系統的熟悉和提升解決問(wèn)題的能力上。另外,保持對老系統熟悉度的最佳方式就是嘗試在老系統中添加代碼。
結論四:每一行代碼都很重要
有時(shí),當我們在編寫(xiě)代碼的時(shí)候,我們可能會(huì )忘記這些代碼最終運行將在生產(chǎn)環(huán)境中,并為一個(gè)真實(shí)用戶(hù)的真實(shí)工作服務(wù)。上面提到的我們親身經(jīng)歷的案例中,僅僅只是因為程序員忘記了釋放 DB 連接(一行代碼而已),就可以干擾一個(gè)用戶(hù)的正常工作(那些工作受影響的用戶(hù)估計很不愿意給我們付錢(qián))。
我的建議是:
想象一下(雖然很難),在世界的另一端,某個(gè)用戶(hù)的工作完全依賴(lài)你編寫(xiě)的代碼,同時(shí)試想一下,你寫(xiě)的每一行代碼都將影響其使用應用的體驗。
在 CI 或者 CD 環(huán)節執行負載測試。如果你想確保代碼高可用,那么就針對每個(gè)即將投產(chǎn)的 PR 或版本都進(jìn)行負載測試。
當你發(fā)現性能問(wèn)題的時(shí)候,請懷疑每一行代碼——據我們的經(jīng)驗,代碼中的每個(gè)字符都有可能是導致性能的瓶頸。
總 結
此文章闡述了我們在系統性能優(yōu)化上的全部經(jīng)驗教訓和體會(huì )心得,我希望通過(guò)此文章能夠幫助你意識到系統性能缺陷所存在的潛在風(fēng)險。
我認為,應用的性能應該被視為最高優(yōu)先處理事項。因為和終端用戶(hù)不能使用系統相比,漂亮的 UI 和炫酷的產(chǎn)品都顯得微不足道。
我寫(xiě)的這些結論都是我根據日常性能優(yōu)化的經(jīng)驗總結而來(lái),因此,在我看來(lái),上面的所有結論都是每一次成功的性能優(yōu)化的基石。所以,我也希望你能發(fā)現它們的用處。
?。?a href="http://www.wxlp666.cn/wechat/">邯鄲微信托管)
