聊聊性能調(diào)優(yōu)什么時(shí)候應(yīng)該停止?
在我以往參與性能優(yōu)化項(xiàng)目的經(jīng)歷中,不止一次有人問到這樣一個(gè)問題:軟件性能調(diào)優(yōu)究竟什么時(shí)候應(yīng)該停止呢?我發(fā)現(xiàn)很多研發(fā)人員在進(jìn)行性能調(diào)優(yōu)的過程中,進(jìn)展往往并不理想。由于性能優(yōu)化目標(biāo)遲遲未能達(dá)成,他們陷入了對性能調(diào)優(yōu)何時(shí)才能結(jié)束的迷茫之中。
其實(shí),這個(gè)問題也曾困擾過我。記得在參與第一個(gè)性能優(yōu)化項(xiàng)目時(shí),我每天的工作就是尋找代碼中的低效率實(shí)現(xiàn),然后進(jìn)行修改重構(gòu),并驗(yàn)證性能提升效果,如此日復(fù)一日。所以,當(dāng)時(shí)我很想說服團(tuán)隊(duì) Leader 結(jié)束這個(gè)性能調(diào)優(yōu)任務(wù),但我首先連自己都說服不了。也正是基于這個(gè)原因,我才開始認(rèn)真思考這個(gè)問題。
為什么會(huì)提出這個(gè)問題?
我們先來做一個(gè)假設(shè),假如現(xiàn)在團(tuán)隊(duì)開發(fā)的一個(gè)軟件產(chǎn)品需要進(jìn)行性能調(diào)優(yōu),其指定的性能調(diào)優(yōu)目標(biāo)為提升 20%。那么,我們來思考一下,這個(gè)目標(biāo)好達(dá)成嗎?實(shí)際上,在進(jìn)行深入的性能分析之前,我們很難回答這個(gè)問題。原因在于,不同軟件的設(shè)計(jì)與實(shí)現(xiàn)存在很大差異,而針對性能這個(gè)模塊,我們可以優(yōu)化提升的空間各不相同。
我舉個(gè)真實(shí)的例子,在我曾經(jīng)參與的一個(gè)協(xié)議棧報(bào)文子系統(tǒng)的性能優(yōu)化項(xiàng)目中,僅僅因?yàn)樵诖a實(shí)現(xiàn)優(yōu)化中減少了一次內(nèi)存拷貝,就一次性將系統(tǒng)處理的性能提升了 20%。然而,在我參與的另一個(gè)配置管理子系統(tǒng)的優(yōu)化項(xiàng)目中,由于沒有找到比較大的性能優(yōu)化點(diǎn),所以花費(fèi)了很長時(shí)間與精力,才將性能提升了 10% 左右。
所以我才說,不同軟件系統(tǒng)的性能優(yōu)化提升效果和優(yōu)化投入成本之間的關(guān)系差異很大,具體可以參考下圖:
圖片
在這個(gè)圖中,有兩個(gè)比較明顯的規(guī)律值得你觀察。其一,不同軟件系統(tǒng)(軟件 A 和軟件 B)在性能調(diào)優(yōu)的過程中,能夠達(dá)到的性能提升百分比上限是不同的。其二,在性能調(diào)優(yōu)的前期,投入很少成本就能獲取比較好的性能提升效果;但在性能調(diào)優(yōu)的中后期,要獲取同樣多的性能收益,需要花費(fèi)的精力和成本會(huì)越來越大。
其實(shí),在進(jìn)行性能調(diào)優(yōu)時(shí),首要追求的目標(biāo)應(yīng)該是最大的投資收益比,也就是獲取的性能優(yōu)化收益值和消耗工作量成本之間的比值要最高。所以在理想情況下,我們應(yīng)該將性能調(diào)優(yōu)目標(biāo)設(shè)定到一個(gè)性能提升臨界值(通常會(huì)接近性能提升的上限)。如果達(dá)到這個(gè)臨界值,就意味著即使后續(xù)進(jìn)行再多的性能調(diào)優(yōu)工作,我們能獲取的性能收益都會(huì)越來越有限。那么在這個(gè)時(shí)候,我們就可以適當(dāng)調(diào)整性能調(diào)優(yōu)的節(jié)奏。如前面的示意圖所示,軟件 A 和軟件 B 的性能調(diào)優(yōu)目標(biāo)設(shè)置的臨界值,可能會(huì)在三角形所標(biāo)識(shí)的位置附近。
但問題在于,對于一個(gè)軟件系統(tǒng)來說,性能調(diào)優(yōu)提升目標(biāo)的臨界值設(shè)定為多少才是合理的呢?我們又該如何確定這個(gè)臨界值呢?
一般情況下,研發(fā)團(tuán)隊(duì)在設(shè)定性能調(diào)優(yōu)目標(biāo)時(shí),會(huì)采取兩種方式。第一種是以客戶關(guān)注的性能需求目標(biāo)為導(dǎo)向。比如我之前參與的百萬表單數(shù)據(jù)查詢分析優(yōu)化項(xiàng)目,其核心目標(biāo)就是讓客戶在操作過程中不卡頓,所以只需把查詢請求響應(yīng)時(shí)間優(yōu)化到 1 秒內(nèi)即可。第二種是以降低產(chǎn)品的部署運(yùn)維成本為導(dǎo)向。這種方式通常會(huì)先確定一個(gè)性能提升百分比,比如將系統(tǒng)服務(wù)的響應(yīng)時(shí)間降低 20%(從 100ms 到 80ms),減少產(chǎn)品部署使用的集群機(jī)器規(guī)模 20% 等等。
不過這里要注意,不管采用哪種方式制定的性能調(diào)優(yōu)目標(biāo),都可能無法與軟件優(yōu)化可以達(dá)到的臨界值完全匹配。在這種場景下,很容易導(dǎo)致性能調(diào)優(yōu)的目標(biāo)沒有達(dá)成,但是性能調(diào)優(yōu)任務(wù)卻無法繼續(xù)開展的情況。
所以,我們在性能調(diào)優(yōu)的過程中,一定要謹(jǐn)記一點(diǎn):未經(jīng)分析就敲定性能優(yōu)化的目標(biāo)是不可取的。既然如此,那么正確開展和實(shí)施性能調(diào)優(yōu)的方法步驟是什么呢?下面我就帶你來分析分析。
正確開展性能調(diào)優(yōu)的方法步驟
實(shí)際上,在很多研發(fā)團(tuán)隊(duì)的心目中,性能調(diào)優(yōu)工作可能就是選擇一款代碼 Profiling 工具,然后針對軟件執(zhí)行期間進(jìn)行性能分析,逐個(gè)尋找熱點(diǎn)函數(shù),最后進(jìn)行修改和優(yōu)化。然而,我們要知道,這種方法存在很大的局限性,它能夠識(shí)別出的性能優(yōu)化點(diǎn)非常有限。
比如說,并發(fā)設(shè)計(jì)、通信設(shè)計(jì)、IO 設(shè)計(jì)等軟件設(shè)計(jì)引入的性能問題,它無法識(shí)別出來;不僅如此,軟件編碼實(shí)現(xiàn)層引入的性能問題,比如數(shù)據(jù)結(jié)構(gòu)和算法選擇等,它也都無法識(shí)別出來。
所以在這里,我根據(jù)以往參與的性能優(yōu)化項(xiàng)目經(jīng)驗(yàn),總結(jié)出了實(shí)施性能調(diào)優(yōu)的方法步驟。接下來,我就給你具體分析一下。
第一步,進(jìn)行系統(tǒng)性的性能優(yōu)化分析診斷。在此過程中,自頂向下地分析并識(shí)別所有可能導(dǎo)致性能劣化的可優(yōu)化點(diǎn)。從這里輸出的內(nèi)容應(yīng)當(dāng)包含軟件設(shè)計(jì)優(yōu)化點(diǎn)、軟件實(shí)現(xiàn)優(yōu)化點(diǎn)等較為完整的列表,例如調(diào)整并發(fā)任務(wù)拆分、調(diào)整數(shù)據(jù)結(jié)構(gòu)、選擇性能優(yōu)化模式等等。
第二步,分析調(diào)整性能調(diào)優(yōu)目標(biāo)值。這一步是指根據(jù)識(shí)別出的性能優(yōu)化點(diǎn),分析修改后的性能提升收益。需要注意的是,針對每個(gè)優(yōu)化點(diǎn)的分析過程各不相同,且并沒有統(tǒng)一的方法可供參考。
為了幫助你更好地理解這個(gè)過程,我舉兩個(gè)以前參與的性能優(yōu)化案例來具體說明。
案例 1:一個(gè)協(xié)議棧報(bào)文子系統(tǒng)的性能優(yōu)化項(xiàng)目。在這個(gè)項(xiàng)目中,我們通過性能優(yōu)化分析診斷后發(fā)現(xiàn),業(yè)務(wù)在處理過程中對報(bào)文數(shù)據(jù)執(zhí)行了一次 copy 操作,而協(xié)議在處理過程中只修改了報(bào)文數(shù)據(jù)頭部很少一部分字節(jié)的信息。在這種場景下,業(yè)務(wù)中的 copy 操作開銷可以優(yōu)化掉。那么優(yōu)化修改后的性能提升值有多少呢?這里我根據(jù) copy 的數(shù)據(jù)量在單板上進(jìn)行了測量計(jì)算,在優(yōu)化修改之前計(jì)算出了性能的預(yù)期收益。
案例 2:一個(gè)后端微服務(wù)的性能優(yōu)化項(xiàng)目。在這個(gè)項(xiàng)目中,經(jīng)過性能優(yōu)化分析診斷后發(fā)現(xiàn),業(yè)務(wù)存在很多慢查詢操作,對軟件性能影響較大。進(jìn)一步分析后發(fā)現(xiàn),這些慢查詢所獲取的數(shù)據(jù)其實(shí)很少變化,所以考慮采用緩存策略來優(yōu)化性能。在這種場景下,可以根據(jù)慢查詢的請求處理時(shí)延和請求的頻次,分析計(jì)算出引入 Cache 場景下的性能提升收益。
總之,對于性能優(yōu)化點(diǎn)來說,性能提升收益分析是一個(gè)非常重要的環(huán)節(jié),不應(yīng)被忽視。
第三步,按照成本收益逐步實(shí)施性能調(diào)優(yōu)。
接下來,我們可以對性能優(yōu)化點(diǎn)按照優(yōu)先級(jí)進(jìn)行排序,然后逐步修改并驗(yàn)證優(yōu)化效果。在對性能優(yōu)化點(diǎn)進(jìn)行排序時(shí),我們需要考慮的主要因素有幾個(gè):性能收益的大小、修改的工作量大小,以及對軟件質(zhì)量產(chǎn)生的影響(比如導(dǎo)致軟件變復(fù)雜、引入故障風(fēng)險(xiǎn)高等)。
另外,這里要記住,如果對編譯期選項(xiàng)配置優(yōu)化和編碼實(shí)現(xiàn)優(yōu)化進(jìn)行優(yōu)先級(jí)排序,在同等性能收益的情況下,一般來說編譯期優(yōu)化的修改工作量會(huì)比較小,引入故障的風(fēng)險(xiǎn)率也比較低,所以優(yōu)先級(jí)應(yīng)該更高一些。
第四步,增加完善性能基線測試。
當(dāng)性能調(diào)優(yōu)完成合入后,就可以同步修改完善性能基線測試。然而,事實(shí)上很少有研發(fā)團(tuán)隊(duì)能夠按照上述步驟來實(shí)施性能調(diào)優(yōu),因此在性能調(diào)優(yōu)過程中容易陷入僵局,花費(fèi)很大精力卻并未給軟件產(chǎn)品帶來價(jià)值提升。在這個(gè)時(shí)候,研發(fā)團(tuán)隊(duì)就應(yīng)該及時(shí)喊停,重新調(diào)整性能調(diào)優(yōu)的工作方式與節(jié)奏。
什么時(shí)候需要喊停性能調(diào)優(yōu)工作?
第一種性能調(diào)優(yōu)反模式是:性能調(diào)優(yōu)嚴(yán)重破壞了軟件的質(zhì)量。
這里舉一個(gè)真實(shí)的案例。在我曾經(jīng)參與的一個(gè)嵌入式系統(tǒng)性能優(yōu)化項(xiàng)目中,原來的性能優(yōu)化團(tuán)隊(duì)發(fā)現(xiàn),通過宏替換個(gè)別函數(shù)調(diào)用會(huì)帶來性能提升,于是幾乎將代碼中的所有函數(shù)都通過宏重新實(shí)現(xiàn)來整改替換。最后導(dǎo)致的后果是:大量的宏實(shí)現(xiàn)函數(shù)導(dǎo)致代碼編寫和閱讀成本顯著增大;同時(shí)在代碼整改的過程中,引入了非常多的故障,而且很長時(shí)間無法得到很好的解決;更糟糕的是,最后的軟件性能優(yōu)化效果也沒有達(dá)到預(yù)期。
其實(shí),這種嚴(yán)重破壞軟件設(shè)計(jì)質(zhì)量的性能調(diào)優(yōu)還是比較普遍的。比如,在代碼中隨意添加條件分支進(jìn)行特殊處理,最后因?yàn)榧尤胩嗵厥饬鞒蹋瑢?dǎo)致代碼很難再添加新的業(yè)務(wù)特性。
第二種性能調(diào)優(yōu)反模式是:盲目修改代碼來嘗試優(yōu)化。
有的性能優(yōu)化團(tuán)隊(duì)為了提升指令 Cache 命中率,會(huì)隨機(jī)調(diào)整函數(shù)的位置。比如,把一個(gè)函數(shù)從一個(gè)文件中搬移到另外一個(gè)文件中;或者把一個(gè)函數(shù)從一個(gè)類搬移到另外一個(gè)類中,來判斷 Cache 命中率是否有提升。這種性能調(diào)優(yōu)方式,由于背后并沒有理論指導(dǎo),即使可以獲取到一些短暫的性能提升收益,也是不穩(wěn)定的,所以我們應(yīng)該盡量避免這樣做。
第三種性能調(diào)優(yōu)反模式是:在業(yè)務(wù)的非性能瓶頸點(diǎn)上反復(fù)調(diào)優(yōu)。
舉個(gè)簡單的例子,軟件的查詢請求處理的吞吐量,受制于底層網(wǎng)絡(luò)傳輸帶寬值的上限,理論上不可能再提升。這個(gè)時(shí)候,還在持續(xù)分析調(diào)優(yōu)軟件實(shí)現(xiàn),期望提升吞吐量是沒有任何意義的。
第四種性能調(diào)優(yōu)反模式是:沒有價(jià)值驅(qū)動(dòng)的性能調(diào)優(yōu)。
其實(shí)這種情況也挺常見,在軟件系統(tǒng)中存在一些服務(wù) / 組件(比如:操作事務(wù)記錄,配置管理后臺(tái)等),它們的處理性能并不會(huì)直接影響用戶感受,而且占用的機(jī)器資源都很少,這時(shí)候如果還投入很大的工作量去優(yōu)化軟件性能,其實(shí)是沒有意義的。