性能調(diào)優(yōu)方法論:如何科學高效地定位性能問題?
一提起軟件系統(tǒng)中的性能問題,或許你首先想到的是 CPU 使用率過高或者內(nèi)存占用率太大,進而致使程序執(zhí)行速度變慢。此時,關(guān)注點往往只停留在軟件實現(xiàn)層面的性能調(diào)優(yōu)上。實際上,這種以最小化資源占用為導向的性能優(yōu)化,其核心目標是降低成本。
然而,對于產(chǎn)品來說,最為關(guān)鍵的其實是從客戶視角所關(guān)注的業(yè)務性能,比如用戶的平均響應時延、99% 的用戶響應時延分布等。這類性能優(yōu)化的核心目標是提升用戶體驗,增強產(chǎn)品的行業(yè)競爭力。
但問題在于,在互聯(lián)網(wǎng)服務領(lǐng)域,從客戶視角去定位分析業(yè)務的性能問題存在一定挑戰(zhàn),主要原因有兩點:
- 針對一些存在業(yè)務性能問題的場景,其系統(tǒng)內(nèi)的服務或組件并不一定處于飽和狀態(tài),所以無法直接從系統(tǒng)資源級監(jiān)控中識別出問題。
- 如果只是個別服務或組件處于飽和狀態(tài),往往可以通過彈性擴展來更快地提升性能體驗,所以這種情況也不是最棘手的性能問題。
再來看看嵌入式領(lǐng)域,以無線通信領(lǐng)域為例,存在很多業(yè)務性能優(yōu)化非??量痰膱鼍埃?FTP 下載速率優(yōu)化、速度平穩(wěn)沒有毛刺優(yōu)化等。在這類系統(tǒng)的實現(xiàn)過程中,導致出現(xiàn)業(yè)務性能問題的原因會更多更復雜,問題可能發(fā)生在鏈路上的任何一個網(wǎng)元設(shè)備內(nèi),或者具體設(shè)備內(nèi)的任何一個軟件組件或硬件單元上。因此,定位分析業(yè)務層性能問題的挑戰(zhàn)會更大。
事實上,定位分析業(yè)務的性能問題是很多程序員都很頭疼的問題。它需要你具備很高的業(yè)務能力,包括對業(yè)務流程的熟悉度、對軟件架構(gòu)及軟件內(nèi)實現(xiàn)邏輯的理解程度,甚至是對操作系統(tǒng)和硬件原理都要有深入的理解。不過,就我的實踐經(jīng)驗來看,即使掌握了這些信息,如果沒有系統(tǒng)的定位分析方法的指導,依舊很難定位出性能問題。
所以,今天這節(jié)課我會給你分享一套性能調(diào)優(yōu)方法論,帶你理解企業(yè)應用系統(tǒng)架構(gòu)的整體邏輯和工作流程,在此基礎(chǔ)上了解引起性能問題的潛在軟硬件瓶頸點,最后介紹系統(tǒng)分析定位的方法。基于這個方法,當你再碰到比較棘手的業(yè)務性能問題時,就可以做到有的放矢,使用這套系統(tǒng)定位分析方法去解決真實的性能問題。
好了,下面我們就來了解下系統(tǒng)的整體架構(gòu)。
系統(tǒng)架構(gòu)視圖
為了能更好地分析與定位復雜的性能問題,你首先需要理解整個系統(tǒng)架構(gòu)視圖,其核心主要包含這三層:產(chǎn)品業(yè)務模型、軟件系統(tǒng)架構(gòu)、組件或服務實現(xiàn),如下圖中所示:
圖片
產(chǎn)品業(yè)務模型:這是系統(tǒng)對外提供的業(yè)務功能與邏輯。以購物流程為例,其對外提供的功能邏輯為:瀏覽商品 —> 添加購物車 —> 查看庫存 —> 支付 —> 發(fā)快遞等。這實際上是站在用戶視角所感知到的與系統(tǒng)發(fā)生交互的過程。這個業(yè)務模型是軟件業(yè)務領(lǐng)域建模階段的重要產(chǎn)物,也是每個系統(tǒng)級產(chǎn)品都應包含的模型。
軟件系統(tǒng)架構(gòu):它表示的是整個軟件系統(tǒng)到具體組件或服務之間的拆分邏輯,以及組件或服務間的交互關(guān)系,如圖中的 A、B、C、E、F 等。這些軟件運行單元可以是一個微服務實例,也可以是一個組件實例,它們會通過通信與交互支撐實現(xiàn)復雜的業(yè)務功能。實際上,不管是嵌入式領(lǐng)域還是互聯(lián)網(wǎng)領(lǐng)域,軟件系統(tǒng)架構(gòu)設(shè)計本質(zhì)上都是對業(yè)務功能拆解的一個過程,通過拆分形成具有獨立清晰邊界的、更小的軟件運行單元。
組件或服務實現(xiàn):這是組件或服務的內(nèi)部代碼實現(xiàn),它會依托于進程、內(nèi)核、硬件的協(xié)作來完成核心的業(yè)務功能。我們知道,系統(tǒng)的業(yè)務性能是由硬件、操作系統(tǒng)、軟件實現(xiàn)以及之上的業(yè)務流程綜合決定的。當我們碰到業(yè)務性能問題時,會基于系統(tǒng)的架構(gòu)視圖從上到下進行分析,最后總能找到具體的制約性能的瓶頸點。
那么,如果你可以提前認識軟硬件中常見的一些性能瓶頸點,了解它們對系統(tǒng)性能的影響,就能夠幫助你更加準確地分析業(yè)務性能問題。但是,很多程序員在定位性能問題時,喜歡只聚焦到某個點上持續(xù)優(yōu)化,而這個點可能并不是性能瓶頸,所以最后很難有比較好的效果。那么,系統(tǒng)潛在的性能瓶頸點都有哪些呢?接下來,我們就一起來看看。
潛在的性能瓶頸點
首先,一般來說,性能瓶頸通常是由一些關(guān)鍵資源使用過度所引起的,并且不同資源使用到達瓶頸(飽和)狀態(tài)對性能產(chǎn)生的影響和規(guī)律各不相同。在計算機系統(tǒng)中,每種硬件資源,如 CPU、Cache、內(nèi)存、磁盤、網(wǎng)絡(luò)接口、總線等,都有可能成為性能瓶頸。這是因為當硬件處理到達飽和狀態(tài)時,會直接導致硬件上的軟件運行性能下降,最終使得業(yè)務性能受到影響。
相比之下,軟件實現(xiàn)所導致的性能問題及影響很容易被忽略。所以今天,我會重點介紹由于軟件實現(xiàn)而引起業(yè)務性能問題的瓶頸點,以便在你分析業(yè)務性能問題的過程中,更好地識別和發(fā)現(xiàn)這些問題。
串行資源受限
第一類典型的瓶頸問題是串行資源(或互斥資源),這是一種可能觸發(fā)業(yè)務性能問題的軟件實現(xiàn)方式。下圖為串行資源的擴展對性能影響的模型圖,它展示了隨著業(yè)務規(guī)模的擴大,對性能所造成的影響。
圖片
如圖中左側(cè)所示,由于串行資源是有限的,隨著業(yè)務請求量的增加,當資源使用飽和后,會導致請求處理吞吐量到達峰值后便無法再提升。同時,如圖的右側(cè)所示,當串行資源使用飽和后,平均處理時延也會因排隊或者阻塞而不斷拉長。在軟件實現(xiàn)中,對性能影響較大的串行資源種類有很多,從粒度從小到大可以包括:互斥鎖、并行設(shè)計中的串行部分、系統(tǒng)依賴的不可擴展的服務或接口等,它們都有著相似的影響。但需要注意的是,在業(yè)務場景中,還有不少資源數(shù)目是大于等于 2 的情況,比如線程池、數(shù)據(jù)庫連接池、其他不能無限擴展的服務或接口。這種有限軟件資源的場景,它們對性能的影響與串行資源對性能的影響較為類似,所以同樣可以參考串行資源對性能影響的分析視圖。
緩沖類資源消息溢出
第二種容易引發(fā)性能問題的軟件實現(xiàn)是緩沖類資源,像緩沖區(qū)、消息隊列、消息中間件等都歸屬于緩沖類資源。緩沖技術(shù)能夠?qū)崿F(xiàn)削峰填谷的機制,從而平滑上游和下游處理速度之間的差異。如下圖所示,倘若緩沖區(qū)設(shè)置過小,當上游請求到達峰值時,可能會致使部分請求被阻塞或者丟棄,進而影響到業(yè)務性能。而如果緩沖區(qū)設(shè)置得越大,其實現(xiàn)削峰填谷的能力就會更強。
但如果緩沖區(qū)設(shè)置得過大,也會造成內(nèi)存資源的浪費,所以緩沖區(qū)大小設(shè)置對性能的影響也很關(guān)鍵。
緩存命中率過低
緩存技術(shù)在軟件實現(xiàn)層面是一項重要的性能優(yōu)化手段,同時也可能成為影響業(yè)務性能的潛在因素。我們了解到,在緩存的使用中有一個關(guān)鍵指標,即緩存命中率,其計算公式為緩存命中個數(shù)除以(緩存命中個數(shù)與緩存未命中個數(shù)之和)。這個指標對業(yè)務性能的影響如下圖所示
圖片
軟件 Bug
最后,軟件實現(xiàn)中存在一個對性能有著極大影響的因素 —— 軟件 Bug。在以往對業(yè)務性能問題進行定位分析的過程中,由軟件 Bug 導致的性能問題并不在少數(shù)。例如,代碼本應是批處理操作,卻因處理錯誤退化為循環(huán)調(diào)用;又或者在運用緩存技術(shù)時,由于緩存 Key 構(gòu)造錯誤,使得緩存永遠無法命中,進而引發(fā)業(yè)務性能驟然下降等情況。
然而,看到這里,你或許會產(chǎn)生疑問:是不是所有的業(yè)務性能問題都是由軟硬件層面的資源性能瓶頸所觸發(fā)的呢?在我看來,并非如此。有些性能問題可能源于業(yè)務模型或者流程本身的問題,軟件和硬件僅僅是其載體。例如,業(yè)務中的某些限速策略會致使處理性能受到限制。另外,在一些更為復雜的系統(tǒng)業(yè)務設(shè)計中,也可能會引入性能問題,這就如同設(shè)計不合理的十字路口紅綠燈一般,會導致嚴重的擁堵狀況。不過,對于這種因業(yè)務模型等因素引發(fā)的性能問題,我們其實可以通過調(diào)整紅綠燈時間,也就是調(diào)整軟件不同模塊的業(yè)務職責和接口實現(xiàn),從而顯著改善擁堵現(xiàn)象。
總而言之,在軟件實現(xiàn)的過程中,可能引發(fā)潛在性能問題的因素眾多。鑒于此,我們需要系統(tǒng)的分析定位方法作為指導,否則將很難準確識別出系統(tǒng)中的所有性能瓶頸點。
所以接下來,我們就一起探討下這個系統(tǒng)分析定位方法吧。
系統(tǒng)分析定位法
實際上,用于分析定位性能問題的方法有不少。像 USE 方法,也就是從檢查各類資源、觀察其使用率飽和的角度去探尋可能存在的性能瓶頸;還有從下往上逐步分析系統(tǒng)中資源使用指標的方法來查找性能瓶頸。另外,還有隨機變動訛方法(這是一種先隨機猜測再進行驗證的方法)、科學實驗法等等。當面對特定的性能問題時,或許每種定位分析方法的效果都不一樣。不過呢,今天我要向你介紹的這種方法,是我依據(jù)以往分析各類性能問題所積累的經(jīng)驗總結(jié)出來的一種方法思路。它相對比較系統(tǒng),而且效率較高,當你在遭遇各種業(yè)務領(lǐng)域的性能問題時,都可以運用這種方法。具體如下圖所示。
圖片
整個定位分析方法從上到下分為三層,分別是業(yè)務模型分析、軟件架構(gòu)分析以及組件或服務實現(xiàn)分析。下面逐一為你介紹。
一、業(yè)務模型分析
業(yè)務模型分析的目標是找出引發(fā)業(yè)務性能問題的業(yè)務觸發(fā)點,并對分析的正確性進行驗證。越是復雜的業(yè)務模型,導致業(yè)務性能問題出現(xiàn)的根本原因可能就越難以察覺。如果在業(yè)務模型分析中確定的根本原因不準確,那么后續(xù)投入再多精力進行深入分析也將是徒勞無功。例如,在分析 TCP 流量下降的性能問題時,可能是下行鏈路出了問題,也可能是上行鏈路存在問題。如果上行鏈路延遲增大,導致 ACK 反饋不及時,進而觸發(fā)擁塞控制,使得 TCP 流量不高。在這種情況下,即便在下行鏈路上花費巨大精力去分析,也不會有任何效果。所以,驗證業(yè)務層性能問題根因分析的結(jié)論是否正確十分必要。在此,我建議你可以通過打樁的方式暫時規(guī)避根因觸發(fā)點,觀察性能問題是否有所改善,以此作為有效的驗證手段。當然,不同系統(tǒng)的業(yè)務模型差異很大,所以業(yè)務模型沒有通用的方法或規(guī)律可循,你只能憑借對業(yè)務邏輯的深入理解,并依據(jù)業(yè)務層實現(xiàn)的運行狀態(tài)監(jiān)控信息來進行分析。當完成業(yè)務模型分析后,你會發(fā)現(xiàn)導致性能問題的原因可能是由某個具體的業(yè)務流程引起的。這時,你就可以針對這個具體業(yè)務流程,深入到軟件架構(gòu)中進一步分析。
二、軟件架構(gòu)分析
在軟件架構(gòu)分析中,我們主要依靠軟件架構(gòu)中組件或服務的接口交互關(guān)系來進行分析。通常對于大型的系統(tǒng)級產(chǎn)品來說,組件或服務間接口的交互信息一定是可以被監(jiān)控、獲取并進行分析的。這樣,根據(jù)獲取的接口交互監(jiān)控信息,我們能夠找到觸發(fā)業(yè)務性能問題的具體組件或服務。此外,和業(yè)務模型分析一樣,我們在軟件架構(gòu)分析階段識別出的存在性能瓶頸的組件或服務,也需要進一步驗證。只有在確保分析結(jié)果正確后,才能進行下一階段的深入分析。我以前在通信領(lǐng)域從事性能問題分析時,每個子系統(tǒng)組件都是由不同的團隊開發(fā)維護的。當面對復雜的業(yè)務性能問題時,我需要沿著子系統(tǒng)組件的接口邊界逐步排查分析,將性能問題交接給下一個子系統(tǒng)組件,并提供充足的分析與驗證信息。但即使在這樣的情況下,仍然可能出現(xiàn)分析錯誤導致返工的情況。所以這一點你一定要注意。
三、軟件內(nèi)部分析
事實上,在互聯(lián)網(wǎng)業(yè)務領(lǐng)域分析性能問題時,無論是業(yè)務模型分析階段還是軟件架構(gòu)分析階段,驗證分析結(jié)論正確性的過程都很容易被我們忽視,從而導致性能問題分析定位出現(xiàn)返工或錯誤。根據(jù)我的實踐經(jīng)驗,當定位到具體的某個組件存在性能瓶頸時,我們就需要深入到這個組件內(nèi)部去分析其具體實現(xiàn),查看這個組件是否存在之前提到的性能瓶頸點,比如串行資源、緩存、軟件 Bug 等,并根據(jù)分析結(jié)果給出優(yōu)化建議。最后,當所有的性能瓶頸點都被解決后,你還需要再次驗證性能問題是否得到改善。如果沒有改善,那么你可能需要重新審視分析過程,或者尋找其他可能的性能瓶頸點。
如何在真實的數(shù)據(jù)分析業(yè)務中應用這套方法論?
這是我曾經(jīng)處理在線數(shù)據(jù)分析業(yè)務中碰到的真實性能問題,當時產(chǎn)品有部分用戶投訴,在 Web 頁面中的查詢數(shù)據(jù)下載功能性能很差,造成用戶等待時間長。而我采用的就是這套性能定位方法,具體定位過程如下圖所示:
圖片
第一階段:進行業(yè)務模型分析,以識別出存在性能問題的業(yè)務流程。在互聯(lián)網(wǎng)服務領(lǐng)域,許多業(yè)務的性能問題是由用戶發(fā)現(xiàn)的,然而在其他業(yè)務領(lǐng)域中,業(yè)務性能瓶頸點則需要依靠業(yè)務領(lǐng)域的監(jiān)控統(tǒng)計,并結(jié)合業(yè)務模型共同分析才能識別出來。就這個案例而言,系統(tǒng)中可能包含眾多的業(yè)務流程。在業(yè)務模型分析階段,我們確定了存在性能問題的業(yè)務流程為 “查詢數(shù)據(jù)下載功能”。具體的用戶業(yè)務流程是:先選擇查詢條件,接著查詢返回數(shù)據(jù),然后生成壓縮數(shù)據(jù),再上傳至對象存儲,最后生成下載鏈接。之后,我們便可以依據(jù)這個業(yè)務流程,去尋找并定位那些引入性能瓶頸的組件和服務。
第二階段:處于軟件架構(gòu)分析階段時,我們能夠根據(jù)存在性能問題的業(yè)務流程,找到由軟件導致性能瓶頸的組件和服務。在這個階段,主要運用系統(tǒng)的微服務間的接口日志進行分析,主要基于 Elasticsearch+Kibana 工具,沿著業(yè)務請求接口鏈路去尋找具體的組件或者服務,最終將性能問題定位到一個確定的微服務組件中。
第三階段:進行組件或服務內(nèi)實現(xiàn)分析。在此階段,深入到導致性能問題的微服務中,通過查看內(nèi)部實現(xiàn)的相關(guān)監(jiān)控或統(tǒng)計信息,發(fā)現(xiàn)導致性能問題的原因是:壓縮數(shù)據(jù)處理與瀏覽統(tǒng)計邏輯使用了相同的計算任務隊列。由于之前的突發(fā)瀏覽業(yè)務,使得隊列中積攢了許多待處理的瀏覽統(tǒng)計任務,進而導致壓縮數(shù)據(jù)處理任務被排隊阻塞,時延變長。這樣一來,經(jīng)過仔細分析后我們會發(fā)現(xiàn),因為用戶無法感知到瀏覽統(tǒng)計邏輯,而壓縮數(shù)據(jù)處理對用戶來說卻比較敏感,所以在這里使用同一個任務隊列,就造成了非關(guān)鍵業(yè)務邏輯對核心業(yè)務的處理時延產(chǎn)生了影響。