曹大帶我學(xué) Go之面向火焰圖編程
你好,我是小X。
曹大最近開(kāi) Go 課程了,小X 正在和曹大學(xué) Go。
這個(gè)系列會(huì)講一些從課程中學(xué)到的讓人醍醐灌頂?shù)臇|西,撥云見(jiàn)日,帶你重新認(rèn)識(shí) Go。
現(xiàn)實(shí)中聽(tīng)過(guò)各種面向 XX 編程,什么面向過(guò)程編程、面向?qū)ο缶幊?也有一些俏皮的,面向薪資編程、面向老板編程;之前曹大還寫(xiě)過(guò)一篇,面向事故編程。今天我們來(lái)講講面向火焰圖編程。
一般我們?cè)谧鲂阅軆?yōu)化的時(shí)候,會(huì)先做壓測(cè),然后進(jìn) pprof 尋找可能的原因及解法。
關(guān)注的指標(biāo),從服務(wù)角度看,包括:
- 請(qǐng)求量
- 錯(cuò)誤數(shù)
- 延遲
從用戶角度看,則是:
- 延遲(Latency)
- 吞吐量(Throughput)
性能優(yōu)化的最終目標(biāo)就是在延遲可以接受的場(chǎng)景下,盡可能提高系統(tǒng)的吞吐量。
對(duì)于 Go 服務(wù),還得看更多:
- 每秒鐘 GC 次數(shù)
- GC 停頓時(shí)長(zhǎng)(p99, max)
- GC 占用的 CPU 大小
- 堆內(nèi)存占用大小
- 協(xié)程數(shù)量
- 申請(qǐng)、釋放的內(nèi)存大小
- 申請(qǐng)的對(duì)象數(shù)
對(duì)性能優(yōu)化而言,我們可以在幾個(gè)層次分別進(jìn)行優(yōu)化:業(yè)務(wù)層、應(yīng)用層、底層。
越在上層優(yōu)化,回報(bào)越高。舉個(gè)簡(jiǎn)單的例子,有業(yè)務(wù)方因?yàn)闅v史原因,服務(wù)啟動(dòng)之后,會(huì)周期性地調(diào)我們的接口拿一些數(shù)據(jù)。但是之后業(yè)務(wù)發(fā)生變動(dòng),拿的數(shù)據(jù)并沒(méi)有被使用,這塊代碼也沒(méi)相應(yīng)地下線。而且因?yàn)閷?duì)方的集群規(guī)模很大,所以這個(gè)調(diào)用量級(jí)還挺大。現(xiàn)在我們服務(wù)的容量即將到頂,需要優(yōu)化服務(wù)或者擴(kuò)容。
如果我們吭哧吭哧地去壓測(cè)、優(yōu)化,擴(kuò)容,很可能也能解決問(wèn)題。并且,優(yōu)化做得好的話,也能體現(xiàn)出自己的價(jià)值。但是平行世界有另一種解法,那就是去梳理業(yè)務(wù)方的使用場(chǎng)景,很可能直接就能下掉一半的訪問(wèn)量,收益會(huì)大很多,而且操作起來(lái)也更簡(jiǎn)單。
但是,通常情況下可能沒(méi)這么好運(yùn),我們還是得對(duì)著火焰圖來(lái)優(yōu)化。
火焰圖的定義也不復(fù)雜:
在 Go 里,一般 pprof web 直接進(jìn)去的圖不太好看懂,我們應(yīng)該看火焰圖 ?;鹧鎴D就看寬度,寬度越寬,表示占用越大。
不怕它高,就怕它寬。
曹大說(shuō),想黑 Go,一張圖片就夠了:
我在這里有 2 個(gè)小點(diǎn)可以分享一下:
- pprof 的火焰圖用當(dāng)前這個(gè) bar 的時(shí)間除以最上層 bar 的時(shí)間,就可以得到某個(gè)函數(shù)的耗時(shí)占比。
- 用當(dāng)前這個(gè) bar 內(nèi)存使用的占比乘以 RSS,得到的值是我們?nèi)绻麑⑦@一塊內(nèi)存使用優(yōu)化掉之后,節(jié)省的內(nèi)存大小。
火焰圖中的平頂山就很值得優(yōu)化。什么是平頂山,最終要優(yōu)化成什么樣子?
一句話,山頂很平的 bar 就叫平頂山??。優(yōu)化之后,平頂山變窄或消失:
但有尖的是不好優(yōu)化的 :
最后總結(jié)一下,面向火焰圖編程,非常簡(jiǎn)單:我們逮著平頂山優(yōu)化就行。
現(xiàn)實(shí)中可能因?yàn)楣镜陌踩块T(mén)設(shè)置了很多阻礙,我們無(wú)法方便地獲取 profile 文件,自然就沒(méi)法愉快地去做性能優(yōu)化了?;A(chǔ)架構(gòu)部門(mén)要做的事情就是盡可能方便地讓研發(fā)獲取到火焰圖。
好了,這就是今天全部的內(nèi)容了~ 我是小X,我們下期再見(jiàn)~