摘要:由此,對(duì)于這樣的場(chǎng)景并不是很友好,那有沒(méi)有能夠精確控制內(nèi)存,讓其在的倍數(shù)時(shí)準(zhǔn)確控制呢內(nèi)存內(nèi)存這就需要出場(chǎng)了。利用這個(gè)特性,就能保證在的一倍時(shí)才能被觸發(fā),這樣就能夠比較精準(zhǔn)控制的觸發(fā)時(shí)機(jī)。
關(guān)于 Go GC 優(yōu)化的手段你知道的有哪些?比較常見(jiàn)的是通過(guò)調(diào)整 GC 的步調(diào),以調(diào)整 GC 的觸發(fā)頻率。
這兩種方式的原理和效果都是一樣的,GOGC 默認(rèn)值是 100,也就是下次 GC 觸發(fā)的 heap 的大小是這次 GC 之后的 heap 的一倍。
我們都知道 GO 的 GC 是標(biāo)記-清除方式,當(dāng) GC 會(huì)觸發(fā)時(shí)全量遍歷變量進(jìn)行標(biāo)記,當(dāng)標(biāo)記結(jié)束后執(zhí)行清除,把標(biāo)記為白色的對(duì)象執(zhí)行垃圾回收。值得注意的是,這里的回收僅僅是標(biāo)記內(nèi)存可以返回給操作系統(tǒng),并不是立即回收,這就是你看到 Go 應(yīng)用 RSS 一直居高不下的原因。在整個(gè)垃圾回收過(guò)程中會(huì)暫停整個(gè) Go 程序(STW),Go 垃圾回收的耗時(shí)還是主要取決于標(biāo)記花費(fèi)的時(shí)間的長(zhǎng)短,清除過(guò)程是非??斓摹?/p>
設(shè)置 GOGC 基本上我們比較常用的 Go GC 調(diào)優(yōu)的方式,大部分情況下其實(shí)我們并不需要調(diào)整 GOGC 就可以,一方面是不涉及內(nèi)存密集型的程序本身對(duì)內(nèi)存敏感程度太低,另外就是 GOGC 這種設(shè)置比率的方式不精確,我們很難精確的控制我們想要的觸發(fā)的垃圾回收的閾值。
GOGC 設(shè)置的非常小,會(huì)頻繁觸發(fā) GC 導(dǎo)致太多無(wú)效的 CPU 浪費(fèi),反應(yīng)到程序的表現(xiàn)就會(huì)特別明顯。舉個(gè)例子,對(duì)于 API 接口來(lái)說(shuō),導(dǎo)致的結(jié)果的就是接口周期性的耗時(shí)變化。這個(gè)時(shí)候你抓取 CPU profile 來(lái)看,大部分的耗時(shí)都集中在 GC 的相關(guān)處理上。
如上圖,這是一次 prometheus 的查詢(xún)操作,我們看到大部分的 CPU 都消耗在 GC 的操作上。這也是生產(chǎn)環(huán)境遇到的,由于 GOGC 設(shè)置的過(guò)小,導(dǎo)致過(guò)多的消耗都耗費(fèi)在 GC 上。
對(duì) API 接口耗時(shí)比較敏感的業(yè)務(wù),由于這種接口一般情況下內(nèi)存占用都比較低,因?yàn)?API 接口變量的生命周期都比較短,這個(gè)時(shí)候 GOGC 置默認(rèn)值的時(shí)候,也可能也會(huì)遇到接口的周期性的耗時(shí)波動(dòng)。這是為什么呢?
因?yàn)檫@種接口本身占用內(nèi)存比較低,每次 GC 之后本身占的內(nèi)存比較低,如果按照上次 GC 后的 heap 的一倍的 GC 步調(diào)來(lái)設(shè)置 GOGC 的話(huà),這個(gè)閾值其實(shí)是很容易就能夠觸發(fā),于是就很容出現(xiàn)接口因?yàn)?GC 的觸發(fā)導(dǎo)致額外的消耗。
那如何調(diào)整呢?是不是把 GOGC 設(shè)置的越大越好呢?這樣確實(shí)能夠降低 GC 的觸發(fā)頻率,但是這個(gè)值需要設(shè)置特別大才有效果,GOGC 一般需要設(shè)置 2000 左右。這樣帶來(lái)的問(wèn)題,GOGC 設(shè)置的過(guò)大,如果這些接口突然接受到一大波流量,由于長(zhǎng)時(shí)間無(wú)法觸發(fā) GC 可能導(dǎo)致 OOM。
由此,GOGC 對(duì)于這樣的場(chǎng)景并不是很友好,那有沒(méi)有能夠精確控制內(nèi)存,讓其在 10G 的倍數(shù)時(shí)準(zhǔn)確控制 GC 呢?
這就需要 Go ballast 出場(chǎng)了。什么是 Go ballast,其實(shí)很簡(jiǎn)單就是初始化一個(gè)生命周期貫穿整個(gè) Go 應(yīng)用生命周期的超大 slice。
func main() { ballast := make([]byte, 10*1024*1024*1024) // 10G // do something runtime.KeepAlive(ballast)}
上面的代碼就初始化了一個(gè) ballast,利用 runtime.KeepAlive 來(lái)保證 ballast 不會(huì)被 GC 給回收掉。
利用這個(gè)特性,就能保證 GC 在 10G 的一倍時(shí)才能被觸發(fā),這樣就能夠比較精準(zhǔn)控制 GO GC 的觸發(fā)時(shí)機(jī)。
這里你可能有一個(gè)疑問(wèn),這里初始化一個(gè) 10G 的數(shù)組,不就占用了 10 G 的物理內(nèi)存呢? 答案其實(shí)是不會(huì)的。
package mainimport ( "runtime" "math" "time")func main() { ballast := make([]byte, 10*1024*1024*1024) <-time.After(time.Duration(math.MaxInt64)) runtime.KeepAlive(ballast)}
$ ps -eo pmem,comm,pid,maj_flt,min_flt,rss,vsz --sort -rss | numfmt --header --to=iec --field 5 | numfmt --header --from-unit=1024 --to=iec --field 6 | column -t | egrep "[t]est|[P]I"%MEM COMMAND PID MAJFL MINFL RSS VSZ0.1 test 12859 0 1.6K 344M 11530184
這個(gè)結(jié)果是在 CentOS Linux release 7.9 驗(yàn)證的,我們看到占用的 RSS 真實(shí)的物理內(nèi)存只有 344M,但是 VSZ 虛擬內(nèi)存確實(shí)有 10G 的占用。
延伸一點(diǎn),當(dāng)懷疑我們的接口的耗時(shí)是由于 GC 的頻繁觸發(fā)引起的,我們需要怎么確定呢?首先你會(huì)想到周期性的抓取 pprof 的來(lái)分析,這種方案其實(shí)也可以,但是太麻煩了。其實(shí)可以根據(jù) GC 的觸發(fā)時(shí)間繪制這個(gè)曲線圖,GC 的觸發(fā)時(shí)間可以利用 runtime.Memstats 的 LastGC 來(lái)獲取。
這張圖相同的流量壓力下,ballast 的表現(xiàn)明顯偏好
本篇文章只是簡(jiǎn)單的闡述了 Go ballast 的使用,不過(guò) Go ballast 是官方比較認(rèn)可的方案,具體可以參見(jiàn) issue 23044。很多開(kāi)源程序,如 tidb,cortex 都實(shí)現(xiàn)了 go ballast,如果你的程序飽受 GOGC 的問(wèn)題影響或者周期性的耗時(shí)不穩(wěn)定,不妨嘗試下 go ballast。
當(dāng)然強(qiáng)烈推薦你看下twitch.tv 這篇文章,相信讓你會(huì)對(duì) GOGC 以及 ballast 的運(yùn)用理解的更加透徹。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/123652.html
摘要:但是強(qiáng)迫癥犯了,為了使得性能達(dá)到極致,再次進(jìn)行了深度的優(yōu)化。把移動(dòng)中心設(shè)置在物體的重力中心,最為舒適。你可以狠狠的點(diǎn)擊預(yù)覽地址到此,組件,無(wú)論從性能,還是手感上來(lái)說(shuō),都已經(jīng)相當(dāng)?shù)姆衔覀兊男枨罅恕? 倉(cāng)庫(kù)地址:Dragact手感絲滑的拖拽布局組件 預(yù)覽地址:支持手機(jī)端噢~ 上回我們說(shuō)到,Dragact組件已經(jīng)進(jìn)行了一系列的性能優(yōu)化,然而面對(duì)大量數(shù)據(jù)的時(shí)候,依舊比較吃力,讓我們來(lái)看看,優(yōu)化...
摘要:但是強(qiáng)迫癥犯了,為了使得性能達(dá)到極致,再次進(jìn)行了深度的優(yōu)化。把移動(dòng)中心設(shè)置在物體的重力中心,最為舒適。你可以狠狠的點(diǎn)擊預(yù)覽地址到此,組件,無(wú)論從性能,還是手感上來(lái)說(shuō),都已經(jīng)相當(dāng)?shù)姆衔覀兊男枨罅恕? 倉(cāng)庫(kù)地址:Dragact手感絲滑的拖拽布局組件 預(yù)覽地址:支持手機(jī)端噢~ 上回我們說(shuō)到,Dragact組件已經(jīng)進(jìn)行了一系列的性能優(yōu)化,然而面對(duì)大量數(shù)據(jù)的時(shí)候,依舊比較吃力,讓我們來(lái)看看,優(yōu)化...
閱讀 2655·2023-04-25 20:50
閱讀 4137·2023-04-25 18:45
閱讀 2285·2021-11-17 17:00
閱讀 3393·2021-10-08 10:05
閱讀 3150·2019-08-30 15:55
閱讀 3587·2019-08-30 15:44
閱讀 2411·2019-08-29 13:51
閱讀 1179·2019-08-29 12:47