架構(gòu)視角的性能優(yōu)化,該怎么做?
性能是一個(gè)很籠統(tǒng)的詞,我們需要一個(gè)完整的方法,對(duì)于性能問(wèn)題進(jìn)行鑒別、分析、解決。本文作者探討的就是如何在復(fù)雜的系統(tǒng)下進(jìn)行優(yōu)化的方法論,讓硬件投入劃得來(lái),讓系統(tǒng)保障可靠的同時(shí)無(wú)比絲滑。一起來(lái)看一下吧。
前言
首先我們的系統(tǒng)通常是非常復(fù)雜的。無(wú)論你的系統(tǒng)是一個(gè)單體應(yīng)用;還是做了n多解耦、分層、拆分的工作,單元邏輯足夠簡(jiǎn)單的分布式應(yīng)用;但是對(duì)于一個(gè)功能視角來(lái)看,仍然非常復(fù)雜,反而分布式環(huán)境下問(wèn)題要比單體應(yīng)用還要復(fù)雜一個(gè)量級(jí)。
本文要說(shuō)的就是:如何在復(fù)雜的系統(tǒng)下進(jìn)行優(yōu)化,讓我們的硬件投入劃得來(lái),讓我們的系統(tǒng)保障可靠的同時(shí)無(wú)比的絲滑。
性能是一個(gè)很籠統(tǒng)的詞兒,很多時(shí)候直接性能優(yōu)化三板斧,只是誤打誤撞的在解決問(wèn)題,我們需要一個(gè)完整的方法,對(duì)于性能問(wèn)題進(jìn)行鑒別、分析、從而解決。本文要探討的就是這部分“方法論”,讓性能優(yōu)化的ROI最大化。
一、什么叫性能好?
要分析性能問(wèn)題,首先我們得有一個(gè)鑒別標(biāo)準(zhǔn),比如:tps承載量、qps承載量、延時(shí)、平均響應(yīng)時(shí)間、每秒IO數(shù)量(IOPS)、負(fù)載、飽和度等等,甚至有些公司內(nèi)會(huì)有一些內(nèi)部約定的指標(biāo),不同的場(chǎng)景下可能直接使用的指標(biāo)是不同的(這樣做是合理的,更簡(jiǎn)單且直接的描述性能),但是如果要把性能優(yōu)化的理論吃透,更從容的解決未知問(wèn)題,需要找到性能描述最本質(zhì)的東西。
個(gè)人認(rèn)為,對(duì)于不同場(chǎng)景進(jìn)行分類(lèi),描述我們系統(tǒng)最恰當(dāng)?shù)淖钤嫉闹笜?biāo)就是吞吐量(對(duì)于容量做考量)和響應(yīng)時(shí)間(對(duì)于時(shí)間做考量),我們要優(yōu)化的就是這兩點(diǎn)。
tps、qps、IOPS這些一定程度上就是在側(cè)面描述吞吐,而平均響應(yīng)時(shí)間、延時(shí)同樣是吞吐量的重要影響部分,對(duì)于大部分場(chǎng)景,我們追求的往往是吞吐量。而某些場(chǎng)景會(huì)最大化追求延時(shí)降級(jí),而非吞吐量。
看到這里可能會(huì)好奇,吞吐和響應(yīng)時(shí)間不是有對(duì)應(yīng)關(guān)系嗎,為啥是兩個(gè)指標(biāo)?
由于單位資源的限定,即時(shí)相同的功能,減少響應(yīng)時(shí)間就是在增大吞吐,而某些情況多犧牲部分資源消耗減少響應(yīng)時(shí)間卻又減少了吞吐(比如極多步并發(fā)處理),圍繞微批處理思路增大延時(shí)卻又增大了吞吐(比如trigger buffer),具體場(chǎng)景具體分析哈,總之要么高吞吐、要么低延遲,更多的時(shí)候是在取折中。
話(huà)題拉回來(lái),我們要知道什么是性能好,才能評(píng)判系統(tǒng),才能進(jìn)行優(yōu)化,才能具體執(zhí)行??傮w來(lái)說(shuō):
以吞吐、延時(shí)為基準(zhǔn)。
- 性能問(wèn)題的優(yōu)化是自上而下的,首先確定系統(tǒng)整體的性能目標(biāo)及評(píng)判標(biāo)準(zhǔn);然后整體評(píng)判
- 其次性能問(wèn)題一定是可拆分的,若干的劣化共同導(dǎo)致了“差”;
- 優(yōu)化的每個(gè)子環(huán)節(jié)應(yīng)該有自身的目標(biāo),而不是對(duì)于整體目標(biāo)的簡(jiǎn)單拆分。根據(jù)子目標(biāo)進(jìn)行分布評(píng)判,有的追求低延時(shí)、有的追求高吞吐、有的要兼顧。
- 子目標(biāo)以對(duì)整體賦能為標(biāo)準(zhǔn),避免局部最優(yōu)解
如何鑒別和判斷:我們拿到吞吐量、響應(yīng)時(shí)間的數(shù)據(jù)之后,有N多的呈現(xiàn)方式。比如說(shuō)平均值、標(biāo)準(zhǔn)方法、百分位數(shù)、中位數(shù)。
對(duì)于性能問(wèn)題來(lái)講平均值參考意義不大,只能大致呈現(xiàn)系統(tǒng)水準(zhǔn),僅在系統(tǒng)整體性能差的情況下有幫助,而大多時(shí)候的性能分析,通常更關(guān)注極端百分位或者異常值,因?yàn)檫@些bad case往往代表了性能的潛在風(fēng)險(xiǎn)及劣化趨勢(shì)。
二、如何優(yōu)化
知道好壞,接下來(lái)談如何優(yōu)化。要談優(yōu)化,首先避免犯錯(cuò),即使不懂成體系的優(yōu)化理論,常見(jiàn)的坑肯定是熟知的,比如說(shuō)慢SQL、for-each call、大量重復(fù)運(yùn)算、各種手工暴力解法。這里不過(guò)多贅述了,大家對(duì)這些常見(jiàn)的性能坑一定很熟悉。
1. 性能優(yōu)化的思路
我們的應(yīng)用程序執(zhí)行是分若干層級(jí)的,從應(yīng)用程序(內(nèi)部又可以分為業(yè)務(wù)程序、中間件程序、庫(kù)函數(shù)),到系統(tǒng)庫(kù),再到系統(tǒng)調(diào)用、最后到內(nèi)核、再到硬件。
就優(yōu)化角度而言,越靠近工作執(zhí)行的地方性能優(yōu)化帶來(lái)的收益就越大,直白點(diǎn)就是越靠近我們業(yè)務(wù)邏輯的優(yōu)化,越有效。按理說(shuō)越底層的東西應(yīng)該對(duì)系統(tǒng)產(chǎn)生的影響越大,那為什么這么說(shuō)呢?
就影響程度而言,越靠近工作執(zhí)行的地方,所能對(duì)系統(tǒng)產(chǎn)生的影響就越大。比如優(yōu)化10條sql的底層存儲(chǔ),”10條sql”-> “1條sql” -> “無(wú)同步sql”差異。就實(shí)現(xiàn)角度和專(zhuān)業(yè)角度而言,越靠近具體工作執(zhí)行的地方,實(shí)現(xiàn)較蠢的可能性越高。
而這些可以匯總為:對(duì)于系統(tǒng)而言會(huì)有“技術(shù)選型”、“不合理使用問(wèn)題”等問(wèn)題,就經(jīng)驗(yàn)和概率來(lái)講,99%的問(wèn)題是因?yàn)檫@部分,如果把所有的性能問(wèn)題進(jìn)行匯總,然后看具體分布圖,不難發(fā)現(xiàn),幾乎都分布在上層(應(yīng)用層)。說(shuō)幾個(gè)問(wèn)題大家感受一下,慢sql(應(yīng)用層)、mysql檢索復(fù)雜度過(guò)高需要優(yōu)化(中間件)、磁盤(pán)IO操作不合理(系統(tǒng)調(diào)用)、磁盤(pán)太慢(硬件層)等問(wèn)題發(fā)生的概率和分布。
總體來(lái)說(shuō),果斷承認(rèn)“99%的問(wèn)題是因?yàn)槲乙粫r(shí)犯蠢或者不太聰明”,才能開(kāi)始逐漸正視性能問(wèn)題和啟動(dòng)性能優(yōu)化工作。所以整體的性能優(yōu)化,應(yīng)該是自頂而下的,由我及外的。
2.“慢”在哪里?
性能問(wèn)題要求一定是可觀(guān)測(cè)的、可量化的,但是我們的系統(tǒng)不一定是可觀(guān)測(cè)的,或者無(wú)法具體量化。這就導(dǎo)致面臨性能低下時(shí),就跟面對(duì)一個(gè)黑盒盲區(qū)一樣,只知道差,卻束手無(wú)策。
這時(shí)就需要對(duì)于我們的系統(tǒng)進(jìn)行剖析,系統(tǒng)必定由n多部分構(gòu)成(比如各種子服務(wù),各種function,各種中間件)除系統(tǒng)構(gòu)成外,我們更應(yīng)該知道系統(tǒng)工作時(shí)的構(gòu)成(每條鏈路的運(yùn)行視圖 — 實(shí)時(shí)運(yùn)行狀態(tài)),然后分析哪些地方出了問(wèn)題。
首先,對(duì)于我們的系統(tǒng)進(jìn)行層層剖析:
尤其是對(duì)于做工程的或者做業(yè)務(wù)的,我們的整體架構(gòu)大多是分布式或者微服務(wù)架構(gòu),如果進(jìn)行層級(jí)、調(diào)用鏈路的拆分通常是如上圖所示。
我們要做的就是對(duì)于系統(tǒng)有一個(gè)更加全面的認(rèn)知,最起碼要回答如下問(wèn)題,可以不用非常細(xì)節(jié),至少要知道一個(gè)概貌:
- 部署環(huán)境&硬件設(shè)施是什么樣子
- 由哪些服務(wù)構(gòu)成
- 用了哪些中間件(&版本 &適配器 &本地優(yōu)化 &調(diào)參)
- 怎么用的中間件(比如redis做緩存,怎么用的,鏈路如何)
- IO鏈路是什么樣子(&對(duì)應(yīng)的協(xié)議 &網(wǎng)絡(luò)處理模型 &放大倍數(shù))
- 調(diào)用鏈路是同步還是異步&有沒(méi)有做批處理
- 怎么用的中間件
- 每個(gè)server功能是什么樣子
在有了整體的概貌之后,就可以對(duì)系統(tǒng)進(jìn)行一定的剖析了,看每一步或者關(guān)鍵步驟是否是支持我們觀(guān)測(cè)的,并且觀(guān)測(cè)手段是可以自動(dòng)化監(jiān)控,還是巡檢機(jī)制,還是case by case。再然后就能可以根據(jù)目標(biāo)對(duì)于這些步驟或者說(shuō)環(huán)節(jié)進(jìn)行量化分析。(最好自動(dòng)化哈)至此大概率就知道我們的系統(tǒng)具體慢在了哪里。
三、對(duì)影響因素有個(gè)大體的感知
先說(shuō)響應(yīng)時(shí)間,首先我們要對(duì)速度有一個(gè)基礎(chǔ)的概念,數(shù)據(jù)沒(méi)那么絕對(duì),但是差不多就是這個(gè)數(shù)量級(jí)先硬件相關(guān):
- 一個(gè)CPU周期:0.3ns
- L1、L2、L3緩存訪(fǎng)問(wèn):0.9ns、2.8ns、12.9ns
- 內(nèi)存訪(fǎng)問(wèn):120ns
- 固態(tài)硬盤(pán):150us
- 機(jī)械硬盤(pán):1ms
- 一次同機(jī)房調(diào)用:1ms
- 一次跨城網(wǎng)絡(luò)傳輸:30ms
- 一次跨專(zhuān)線(xiàn)地域傳輸:100 – 200ms
再包裝下看日常的操作耗時(shí):
- 一條sql call(索引合理,數(shù)據(jù)量正常):1-2ms
- 一次RPC調(diào)用:1-10ms
- 一次redis操作(無(wú)大key、熱key):1-2ms
- 一次kafka send(帶buffer):1ms以?xún)?nèi)
- 一次http請(qǐng)求:5ms
對(duì)于CPU的消耗程度,如果把CPU看作是穩(wěn)定的(相對(duì)有點(diǎn)粗暴哈),消耗程度通常可以用CPU占用時(shí)間來(lái)表述(onCPU、offCPU)。比如完成一次md5需要多少時(shí)鐘、執(zhí)行磁盤(pán)IO需要多少時(shí)鐘、一次網(wǎng)絡(luò)IO需要多少時(shí)鐘等等。
而這個(gè)東西具體的表象其實(shí)就是cpu使用率,我們不難可以看到各個(gè)進(jìn)程、各個(gè)現(xiàn)成的占用程度,如果再掛一下火焰圖不難看出哪些操作對(duì)CPU消耗更高及對(duì)應(yīng)占比。
各個(gè)響應(yīng)時(shí)間和CPU消耗程度是對(duì)吞吐和響應(yīng)時(shí)間最本質(zhì)的影響,要進(jìn)行性能優(yōu)化就是對(duì)于CPU占用和響應(yīng)時(shí)間(處理延時(shí))進(jìn)行優(yōu)化,各種方法減少CPU動(dòng)作、減少延時(shí)等待,應(yīng)用層的優(yōu)化就是奔著這些目的去的。
1. 優(yōu)化延時(shí)
應(yīng)用層面 關(guān)于延時(shí)我們?cè)撊绾芜M(jìn)行優(yōu)化呢?整體來(lái)看的話(huà):減少操作、減少等待。說(shuō)幾個(gè)常見(jiàn)的策略:
- 能否減少操作,可以對(duì)于一次請(qǐng)求、一次任務(wù)的執(zhí)行步驟進(jìn)行梳理,分一下類(lèi),核心工作是哪些,哪些工作是可以從核心鏈路摘除的。
- 能否有復(fù)雜度更低的動(dòng)作,比如檢索算法是否可以?xún)?yōu)化、序列化算法是否可以?xún)?yōu)化、是否有更高效的數(shù)據(jù)結(jié)構(gòu)和算法。
- 能否打時(shí)間差,前置處理或后置處理,比如初始化動(dòng)作前置(不光是對(duì)象初始化,業(yè)務(wù)動(dòng)作也行,可以提前計(jì)算、提前開(kāi)戶(hù)等),后置比如異步化處理,發(fā)獎(jiǎng)券之類(lèi)的
- 能否緩存&復(fù)用,請(qǐng)求處理的結(jié)果、中間過(guò)程、或者socket鏈接是否可以直接復(fù)用,各種池化技術(shù)。
- 能否并行,多步并行處理,減少整體耗時(shí),衡量下并行帶來(lái)的收益,是否比實(shí)現(xiàn)并行的代價(jià)高。
- 能否非阻塞并發(fā)處理,減少等待,避免大量的等待操作,業(yè)務(wù)處理的劣根性大多源于此。
- 能否提前失敗,對(duì)于易失敗請(qǐng)求,提前進(jìn)行失敗性檢查,避免正常資源的占用,引起其他請(qǐng)求等待。
- 能否繼續(xù)優(yōu)化中間件操作,是否有更高效的中間件選型,操作上是否有更多的優(yōu)化空間。
- 能否無(wú)”鎖“化處理,鎖是導(dǎo)致等待的核心因素之一,但這里是泛指可能讓我們線(xiàn)程發(fā)生阻塞的情況,盡可能的減少同步鏈路中的等待機(jī)制可以讓我們的響應(yīng)時(shí)間更容易得到保證。
以余額支付系統(tǒng)交互信息流程舉個(gè)例子(省了很多步驟,粗略描述):
嘗試優(yōu)化一下
系統(tǒng)層面(假設(shè)包含虛擬機(jī)),只是舉幾個(gè)例子
垃圾回收中斷是否影響過(guò)大,poll還是epoll、水平觸發(fā)還是邊緣觸發(fā),fsync還是flush,線(xiàn)程的CPU親和,hardware 是否有特異性?xún)?yōu)化,SSD還是機(jī)械硬盤(pán),設(shè)配新舊程度。
2. 優(yōu)化吞吐
接下來(lái)看下吞吐的相關(guān)優(yōu)化,吞吐量指的是現(xiàn)有系統(tǒng)在單位時(shí)間內(nèi)能夠處理的請(qǐng)求或者任務(wù)數(shù)量。而對(duì)于吞吐的優(yōu)化通常有兩點(diǎn):
- 單位資源內(nèi)能夠具備更大的吞吐量,提高系統(tǒng)資源利用率。
- 保證吞吐量沒(méi)有瓶頸,一定程度上,可以無(wú)限橫向擴(kuò)展。
先看第一個(gè)問(wèn)題,如何讓單位資源內(nèi)承載更多的吞吐。
影響吞吐的因素有很多,比如前面剛剛提到的響應(yīng)時(shí)間,關(guān)于響應(yīng)時(shí)間和吞吐量的關(guān)系前面已經(jīng)描述過(guò)了,大部分場(chǎng)景下適當(dāng)?shù)臏p少延時(shí)對(duì)于吞吐的影響是線(xiàn)性增長(zhǎng)的,如何降低響應(yīng)時(shí)間參照前一段的方案(大部分是正向的),唯一需要注意的是,在有限的資源下,過(guò)度的優(yōu)化是會(huì)帶來(lái)吞吐下降的,要做的是盡可能在不帶來(lái)CPU增長(zhǎng)的情況降低響應(yīng)時(shí)間。
常用的技巧技巧批處理,比如多次IO是否可以進(jìn)行合并,批處理一下,減少多次鏈接開(kāi)銷(xiāo),這樣對(duì)整體吞吐帶來(lái)的威力是很大的。對(duì)同步批處理,一定程度上也算是對(duì)于響應(yīng)時(shí)間的調(diào)整,對(duì)于整體平均響應(yīng)時(shí)間是在下降的,但是對(duì)于頭部請(qǐng)求響應(yīng)時(shí)間是被劣化的。
但通常的使用往往是異步化處理 + 批處理,IO 緩沖區(qū)、buffer triger、insert buffer、kafka send buffer 都是這個(gè)思路。帶來(lái)的吞吐和響應(yīng)時(shí)間提升通常是炸裂的。
接下來(lái)看第二個(gè)問(wèn)題,解決吞吐瓶頸。
當(dāng)完成單位資源的吞吐優(yōu)化之后,按理說(shuō)有訴求就水平擴(kuò)容即可,但是實(shí)時(shí)并非如此,經(jīng)常會(huì)出現(xiàn)一個(gè)“熱點(diǎn)”成為系統(tǒng)的吞吐瓶頸,尤其是在OLTP系統(tǒng)中,熱點(diǎn)會(huì)以各種各樣的方式出現(xiàn),但是通常都和狀態(tài)強(qiáng)相關(guān),比如說(shuō)全局庫(kù)存、熱點(diǎn)用戶(hù)、熱點(diǎn)機(jī)器等等。
如果要優(yōu)化,這里就不得不提CAP理論了,在數(shù)據(jù)多節(jié)點(diǎn)分布的情況下,為了保障一致性,系統(tǒng)整體的可用性必然會(huì)受到影響,可用性下降,最大的表現(xiàn)其實(shí)就是有效吞吐的下降。突破瓶頸,持續(xù)放大吞吐,那就適當(dāng)?shù)臓奚幌聰?shù)據(jù)的一致性吧。
要做的是把熱點(diǎn)數(shù)據(jù)進(jìn)行割裂,然后犧牲一致性,也就是把“熱點(diǎn)”進(jìn)行sharding,讓熱點(diǎn)也能進(jìn)行進(jìn)行水平擴(kuò)容,然后在這些短暫的不一致之上打補(bǔ)丁,盡快達(dá)成最終一致。
四、負(fù)載對(duì)于性能的影響
1. 劣化現(xiàn)象
除了我們代碼的實(shí)現(xiàn)、系統(tǒng)的構(gòu)成會(huì)對(duì)系統(tǒng)有一定的影響,瀕臨負(fù)載極限的時(shí)候不管是吞吐量、響應(yīng)時(shí)間都會(huì)受到一定程度的影響。
對(duì)吞吐而言,在機(jī)器資源一定的情況下,并不是隨負(fù)載一直線(xiàn)性變化的,到達(dá)一定的臨界值后如果持續(xù)增加負(fù)載,吞吐通常會(huì)由線(xiàn)性增長(zhǎng)進(jìn)入緩慢增長(zhǎng)的,如果再持續(xù)的增加負(fù)載,會(huì)出現(xiàn)一定的劣化現(xiàn)象(比之前的吞吐量還會(huì)降低),這在JVM等虛擬機(jī)之上運(yùn)行的應(yīng)用,或者在池化排隊(duì)機(jī)制的加持下愈發(fā)嚴(yán)重和明顯。
對(duì)響應(yīng)時(shí)間而言,在機(jī)器資源一定的情況下,也不會(huì)隨始終保持耗時(shí)不變,同樣在到達(dá)負(fù)載臨界值時(shí),會(huì)發(fā)成程度不一的劣化現(xiàn)象,有的響應(yīng)時(shí)間增長(zhǎng)迅速,有的則呈慢速下降。
2. 劣化的原因
這是為什么呢,因?yàn)樵谪?fù)載到達(dá)一定閾值時(shí)會(huì)觸發(fā)程度不一的系統(tǒng)資源搶占問(wèn)題,比如大量的排隊(duì)等待處理,此時(shí)上下文切換會(huì)更加的頻繁,并且對(duì)于某些JVM等虛擬機(jī)之上的運(yùn)行的應(yīng)用還會(huì)帶來(lái)一定程度上的內(nèi)存清理(分配和回收)及維護(hù)代價(jià)進(jìn)而導(dǎo)致競(jìng)爭(zhēng)更加激烈,也就導(dǎo)致了性能被進(jìn)一步劣化。
這也是為什么很多中間件會(huì)限制最大鏈接數(shù)、最大線(xiàn)程數(shù)、最大排序序列的原因,而對(duì)于我們業(yè)務(wù)應(yīng)用程序而言也是一樣的,在進(jìn)行池化處理排隊(duì)機(jī)制時(shí)一定要明確合適拒絕。
并且我們應(yīng)該對(duì)于我們的的服務(wù)加以保護(hù),以此保證負(fù)載不會(huì)出現(xiàn)這種劣化現(xiàn)象,比如說(shuō)限流、限并發(fā),比如說(shuō)tomcat把參數(shù)調(diào)整的合理一些,讓負(fù)載,比如說(shuō)CPU最大不超過(guò)60%、70%。
3. 這里有個(gè)大坑 – 百分之90的問(wèn)題是因?yàn)檫@個(gè)
除了到達(dá)負(fù)載臨界值時(shí)會(huì)出現(xiàn)這個(gè)問(wèn)題,在“驟發(fā)的流量”面前這個(gè)問(wèn)題也非常的凸顯,因?yàn)榇罅康某跏蓟ぷ鳎ㄦ溄咏?、線(xiàn)程池?cái)U(kuò)容、client初始化等等),因?yàn)榭D問(wèn)題或者延遲變高等問(wèn)題導(dǎo)致排隊(duì)激化,同時(shí)機(jī)器負(fù)載也會(huì)驟然上升,導(dǎo)致負(fù)載臨界問(wèn)題或者時(shí)臨界值提前到來(lái)。日??幢O(jiān)控,突發(fā)流量時(shí)的尖刺,90%的原因都是這個(gè)。
這一點(diǎn)一定要額外注意,大流量前充分預(yù)熱、保持緩存熱度、高性能場(chǎng)景放棄懶加載,極端情況下適當(dāng)擴(kuò)大活躍線(xiàn)程數(shù)、鏈接?;疃际鞘种匾摹?/p>
4. 日常的負(fù)載要保持多少
日常應(yīng)用的負(fù)載通常由服務(wù)器資源的瓶頸負(fù)載所決定,CPU爭(zhēng)搶會(huì)劣化,內(nèi)存爭(zhēng)搶發(fā)生換頁(yè)情況更糟糕。那我們?nèi)粘5呢?fù)載到底應(yīng)該在多少合適,這里以CPU負(fù)載為例來(lái)進(jìn)行推導(dǎo):
通常經(jīng)驗(yàn)值是60%或者70%,在對(duì)穩(wěn)定性要求極高的場(chǎng)景可能會(huì)控制的更低一些,這個(gè)值是怎么得來(lái)的?
首先CPU負(fù)載超過(guò)90%就會(huì)有概率發(fā)生劣化現(xiàn)象,CPU并非你想象的那么穩(wěn)定性能方面會(huì)有抖動(dòng)的;
其次即使隔離部署,操作系統(tǒng)之上運(yùn)行了不止你一個(gè)應(yīng)用程序的進(jìn)程,可能會(huì)有一些重操作的client,比如log拉取,如果log還在客戶(hù)端做了grep、awk等處理那可能影響更重,這部分的buffer要留出來(lái);
其次我們的進(jìn)程的CPU消耗并不是線(xiàn)性不變的,仔細(xì)看看監(jiān)控會(huì)發(fā)現(xiàn)忽高忽低,這部分buffer要留出來(lái);
我們很難保證下游不發(fā)生抖動(dòng),如果下游抖動(dòng)發(fā)生了一定程度的抖動(dòng),但還未超時(shí),一定概率會(huì)導(dǎo)致主調(diào)server發(fā)生排隊(duì),進(jìn)而可能發(fā)生雪崩效應(yīng),放大問(wèn)題,這時(shí)候產(chǎn)生的劣化波動(dòng)也是要能承受的,同樣的也需要一定的buffer。
同樣的,我們也很難保證主調(diào)方不會(huì)發(fā)生合理程度內(nèi)的激增現(xiàn)象,驟然的CPU波動(dòng)也是合理的,這部分buffer要留出來(lái)。
干掉這些buffer,通常經(jīng)驗(yàn)值是60%上下浮動(dòng),如果單請(qǐng)求消耗資源極多并且可用性要求極高那可能多留點(diǎn)buffer,否則就少點(diǎn),然后對(duì)應(yīng)的平穩(wěn)時(shí)對(duì)應(yīng)CPU負(fù)載所能承載的負(fù)載就是我們應(yīng)該設(shè)定的日常負(fù)載,再由此推出限流值、動(dòng)態(tài)擴(kuò)縮標(biāo)準(zhǔn)等等。
5. 熱門(mén)問(wèn)題 – 語(yǔ)言的差異到底有多大
語(yǔ)言是個(gè)有趣的問(wèn)題,也是一個(gè)爭(zhēng)論已久的問(wèn)題,這里進(jìn)行簡(jiǎn)單的討論哈,通常我們的變成語(yǔ)言會(huì)分為編譯型語(yǔ)言和解釋型語(yǔ)言,還有些語(yǔ)言既有解釋器,又有編譯器,不用糾結(jié)概念,就從解釋執(zhí)行和編譯執(zhí)行的角度看問(wèn)題即可。
編譯型比如說(shuō)C/C++,編譯過(guò)的代碼總體來(lái)說(shuō)是高性能的,因?yàn)樵贑PU執(zhí)行執(zhí)行時(shí)不需要額外的一層映射,并且機(jī)器代碼總是原始代碼映射的很緊密,當(dāng)然啦,很大程度取決于編譯器的編譯優(yōu)化。
解釋型如說(shuō)Java(純解釋執(zhí)行的話(huà),拋開(kāi)JIT不談),需要額外的一層解釋工作,會(huì)增加不少的開(kāi)銷(xiāo),通常不會(huì)被期待有很強(qiáng)大的性能。
對(duì)于解釋器和編譯器共存的語(yǔ)言Java(帶上JIT了),性能好壞主要看JIT的優(yōu)化力度,想觀(guān)測(cè)的話(huà)可以打開(kāi)JIT日志,看下你的代碼到底哪些進(jìn)行最徹底的優(yōu)化(JIT 優(yōu)化層級(jí)是4),然后看哪些操作會(huì)導(dǎo)致退優(yōu)化的發(fā)生,JIT的決策器也非常的關(guān)鍵。但是這種體系下,性能分析會(huì)相對(duì)費(fèi)勁一些,JIT的優(yōu)化策略(決策、編譯)很難說(shuō)對(duì)所有開(kāi)發(fā)者都是白盒的,并且在真正執(zhí)行的時(shí)候,和我們代碼的映射已經(jīng)幾乎匹配不上了(還好Java的性能分析工具集夠全)。
除此之外,語(yǔ)言的垃圾回收機(jī)制雖然帶來(lái)的很多開(kāi)發(fā)的便捷性,但是對(duì)于性能要求極高的場(chǎng)景,垃圾回收會(huì)帶來(lái)額外的影響,比如說(shuō)程序的停頓,內(nèi)存中對(duì)象的掃描、索引、復(fù)制工作。
五、性能優(yōu)化的時(shí)機(jī)和判斷
1. 性能優(yōu)化的時(shí)機(jī)
什么時(shí)機(jī)進(jìn)行性能優(yōu)化,常見(jiàn)的有“系統(tǒng)創(chuàng)建時(shí)”、“發(fā)生改變時(shí)”、“問(wèn)題暴露時(shí)”、“擺爛-重新寫(xiě)”,這個(gè)業(yè)界并沒(méi)有一個(gè)標(biāo)準(zhǔn)的答案,個(gè)人的處理思路是:在系統(tǒng)創(chuàng)建時(shí)滿(mǎn)足近1年半左右的性能訴求就足夠了,剩下的交給將來(lái)。
系統(tǒng)設(shè)計(jì)的初期肯定會(huì)進(jìn)行系統(tǒng)的定位分析及對(duì)應(yīng)的邊界劃分,此時(shí)系統(tǒng)應(yīng)該具備哪些功能、應(yīng)該被哪些場(chǎng)景所使用就已經(jīng)確定了,我們要做的就是對(duì)這部分內(nèi)容進(jìn)行預(yù)判,這應(yīng)該是屬于架構(gòu)設(shè)計(jì)很核心的一部分,并且在設(shè)計(jì)的過(guò)程中,如果預(yù)判有50%以上場(chǎng)景會(huì)發(fā)生性能要求的突變,那么我們就應(yīng)該給系統(tǒng)留足擴(kuò)展性。
架構(gòu)設(shè)計(jì)思路中有種思想叫做“演進(jìn)式架構(gòu)”,這里推崇的就是這個(gè)觀(guān)點(diǎn)。
但需要額外注意的是,我們可以不做過(guò)多的性能優(yōu)化設(shè)計(jì),但是要做足性能優(yōu)化分析的設(shè)計(jì),正如文章最開(kāi)始所提到的,我們要保證系統(tǒng)是可觀(guān)測(cè)、可量化的。
上面講的是設(shè)計(jì)側(cè)的優(yōu)化問(wèn)題,在系統(tǒng)發(fā)生變更時(shí),如果通過(guò)分析工具和監(jiān)測(cè)工具發(fā)現(xiàn)有性能劣化的現(xiàn)象,是一定要進(jìn)行優(yōu)化動(dòng)作的,放任性能問(wèn)題不管一定會(huì)阻礙我們系統(tǒng)的進(jìn)程,技術(shù)債早晚堆成山。
2. 減少局部最優(yōu)解
局部最優(yōu)解是一個(gè)數(shù)學(xué)求解的最優(yōu)化問(wèn)題,我們?cè)O(shè)計(jì)實(shí)現(xiàn)的摸索,也可以粗暴的看作是一個(gè)最優(yōu)的求解問(wèn)題,那么理論上也是會(huì)存在局部最優(yōu)解問(wèn)題的。
實(shí)踐過(guò)程也確實(shí)如此,相信大家都經(jīng)歷過(guò)大規(guī)模的重構(gòu)。因?yàn)樾阅軆?yōu)化方案選擇絕對(duì)不止一條路,再有拆分到子方案岔路就變的更多了,在選擇的過(guò)程中很容易發(fā)生局部最優(yōu)解問(wèn)題。
就整體方案選擇而言
在進(jìn)行系統(tǒng)設(shè)計(jì)的時(shí)候,因?yàn)楫?dāng)前的系統(tǒng)設(shè)計(jì)整體方案不合理,在一個(gè)相對(duì)偏差的方向上進(jìn)行了極致的優(yōu)化,導(dǎo)致性能看起是得到了解決,并且段時(shí)間內(nèi)沒(méi)有問(wèn)題,但是在后期的發(fā)展過(guò)程中很容易導(dǎo)致性能優(yōu)化停止不前。所以進(jìn)行性能問(wèn)題設(shè)計(jì)的時(shí)候,應(yīng)該更多的比較各個(gè)方案的差異性,以及可發(fā)展性。多去探索未知的未知,才能讓我們的方案更加合理。
就方案拆分而言
架構(gòu)設(shè)計(jì)應(yīng)該是一個(gè)“一鍋出”的過(guò)程,一定要有一個(gè)上層指導(dǎo),不要求每個(gè)子模塊要用何種方案,但是一定要有明確的上層指導(dǎo)目標(biāo),這樣在選擇時(shí)就避免方向上的偏差,不至于每個(gè)子模塊都是自己域內(nèi)最合理的方案,但拼湊在一起確發(fā)現(xiàn)壓根解決不了問(wèn)題。
3. 性能分析工具
首先基礎(chǔ)架構(gòu)一定提供了足夠全的分析工具,所在的公司也肯定有人在搞定針對(duì)基礎(chǔ)架構(gòu)的探測(cè)分析及業(yè)務(wù)系統(tǒng)分析的基礎(chǔ)支持,找到對(duì)應(yīng)的人,然后問(wèn)他們。
要是進(jìn)行學(xué)習(xí)或者文檔檢索,提供一點(diǎn)關(guān)鍵詞,火焰圖、探針、優(yōu)化分析、診斷工具、perf、profiling、Trace、netstat、iostat、vmstat、jstack、top、slabtop、ps。
這種資料應(yīng)該一搜一大片……
六、寫(xiě)在最后
整體算是一點(diǎn)自己對(duì)于性能問(wèn)題分析及設(shè)計(jì)優(yōu)化相關(guān)的方法論總結(jié),文章里面并沒(méi)有涉及過(guò)多的細(xì)節(jié)方案,核心原因是想“以漁”。另外市面上大多的直接方案,導(dǎo)致小朋友們習(xí)慣性的三板斧,個(gè)人覺(jué)著這種導(dǎo)向性不算良好,應(yīng)該更清楚為什么這么做,才能更好的解決問(wèn)題吧。
除此之外,本文的內(nèi)容實(shí)在是有點(diǎn)扯,建議通過(guò)一些系統(tǒng)實(shí)踐來(lái)反觀(guān)我所描述的這些方法和觀(guān)點(diǎn),個(gè)人經(jīng)歷過(guò)的覺(jué)著收益匪淺的系統(tǒng):支付相關(guān)-比如paycore、交易收單、推薦相關(guān)、廣告相關(guān)-比如DSP、營(yíng)銷(xiāo)活動(dòng)系統(tǒng)。
作者:鄒志全
來(lái)源:https://mp.weixin.qq.com/s/513BSGZoTWzeVAp6KDTHsA
本文由 @一個(gè)數(shù)據(jù)人的自留地 授權(quán)發(fā)布于人人都是產(chǎn)品經(jīng)理,未經(jīng)作者許可,禁止轉(zhuǎn)載
題圖來(lái)自 Unsplash,基于 CC0 協(xié)議
該文觀(guān)點(diǎn)僅代表作者本人,人人都是產(chǎn)品經(jīng)理平臺(tái)僅提供信息存儲(chǔ)空間服務(wù)。
- 目前還沒(méi)評(píng)論,等你發(fā)揮!