成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

性能優化 | Go Ballast 讓內存控制更加絲滑

存儲 存儲軟件
關于 Go GC 優化的手段你知道的有哪些?比較常見的是通過調整 GC 的步調,以調整 GC 的觸發頻率。

[[435409]]

關于 Go GC 優化的手段你知道的有哪些?比較常見的是通過調整 GC 的步調,以調整 GC 的觸發頻率。

  • 設置 GOGC
  • 設置 debug.SetGCPercent()

這兩種方式的原理和效果都是一樣的,GOGC 默認值是 100,也就是下次 GC 觸發的 heap 的大小是這次 GC 之后的 heap 的一倍。

我們都知道 GO 的 GC 是標記-清除方式,當 GC 會觸發時全量遍歷變量進行標記,當標記結束后執行清除,把標記為白色的對象執行垃圾回收。值得注意的是,這里的回收僅僅是標記內存可以返回給操作系統,并不是立即回收,這就是你看到 Go 應用 RSS 一直居高不下的原因。在整個垃圾回收過程中會暫停整個 Go 程序(STW),Go 垃圾回收的耗時還是主要取決于標記花費的時間的長短,清除過程是非常快的。

設置 GOGC 的弊端

1. GOGC 設置比率的方式不精確

設置 GOGC 基本上我們比較常用的 Go GC 調優的方式,大部分情況下其實我們并不需要調整 GOGC 就可以,一方面是不涉及內存密集型的程序本身對內存敏感程度太低,另外就是 GOGC 這種設置比率的方式不精確,我們很難精確的控制我們想要的觸發的垃圾回收的閾值。

2. GOGC 設置過小

GOGC 設置的非常小,會頻繁觸發 GC 導致太多無效的 CPU 浪費,反應到程序的表現就會特別明顯。舉個例子,對于 API 接口來說,導致的結果的就是接口周期性的耗時變化。這個時候你抓取 CPU profile 來看,大部分的耗時都集中在 GC 的相關處理上。

如上圖,這是一次 prometheus 的查詢操作,我們看到大部分的 CPU 都消耗在 GC 的操作上。這也是生產環境遇到的,由于 GOGC 設置的過小,導致過多的消耗都耗費在 GC 上。

3. 對某些程序本身占用內存就低,容易觸發 GC

對 API 接口耗時比較敏感的業務,如果 GOGC 置默認值的時候,也可能也會遇到接口的周期性的耗時波動。這是為什么呢?

因為這種接口本身占用內存比較低,每次 GC 之后本身占的內存比較低,如果按照上次 GC 后的 heap 的一倍的 GC 步調來設置 GOGC 的話,這個閾值其實是很容易就能夠觸發,于是就很容出現接口因為 GC 的觸發導致額外的消耗。

4. GOGC 設置很大,有的時候又容易觸發 OOM

那如何調整呢?是不是把 GOGC 設置的越大越好呢?這樣確實能夠降低 GC 的觸發頻率,但是這個值需要設置特別大才有效果。這樣帶來的問題,GOGC 設置的過大,如果這些接口突然接受到一大波流量,由于長時間無法觸發 GC 可能導致 OOM。

由此,GOGC 對于某些場景并不是很友好,那有沒有能夠精確控制內存,讓其在 10G 的倍數時準確控制 GC 呢?

GO 內存 ballast

這就需要 Go ballast 出場了。什么是 Go ballast,其實很簡單就是初始化一個生命周期貫穿整個 Go 應用生命周期的超大 slice。

  1. func main() { 
  2.   ballast := make([]byte, 10*1024*1024*1024) // 10G  
  3.    
  4.   // do something 
  5.    
  6.   runtime.KeepAlive(ballast) 

上面的代碼就初始化了一個 ballast,利用 runtime.KeepAlive 來保證 ballast 不會被 GC 給回收掉。

利用這個特性,就能保證 GC 在 10G 的一倍時才能被觸發,這樣就能夠比較精準控制 GO GC 的觸發時機。

這里你可能有一個疑問,這里初始化一個 10G 的數組,不就占用了 10 G 的物理內存呢? 答案其實是不會的。

  1. package main 
  2.  
  3. import ( 
  4.     "runtime" 
  5.     "math" 
  6.     "time" 
  7.  
  8. func main() { 
  9.     ballast := make([]byte, 10*1024*1024*1024) 
  10.  
  11.     <-time.After(time.Duration(math.MaxInt64)) 
  12.     runtime.KeepAlive(ballast) 
  1. $ 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" 
  2.  
  3. %MEM  COMMAND   PID    MAJFL      MINFL  RSS    VSZ 
  4. 0.1   test      12859  0          1.6K   344M   11530184 

這個結果是在 CentOS Linux release 7.9 驗證的,我們看到占用的 RSS 真實的物理內存只有 344M,但是 VSZ 虛擬內存確實有 10G 的占用。

延伸一點,當懷疑我們的接口的耗時是由于 GC 的頻繁觸發引起的,我們需要怎么確定呢?首先你會想到周期性的抓取 pprof 的來分析,這種方案其實也可以,但是太麻煩了。其實可以根據 GC 的觸發時間繪制這個曲線圖,GC 的觸發時間可以利用 runtime.Memstats 的 LastGC 來獲取。

生產環境驗證

  • 綠線 調整前 GOGC = 30
  • 黃線 調整后 GOGC 默認值,ballast = 100G

這張圖相同的流量壓力下,ballast 的表現明顯偏好。

結論

本篇文章只是簡單的闡述了 Go ballast 的使用,Go ballast 是官方比較認可的方案,具體可以參見 issue 23044[1]。很多開源程序,如 tidb[2],cortex[3] 都實現了 go ballast,如果你的程序飽受 GOGC 的問題影響或者周期性的耗時不穩定,不妨嘗試下 go ballast。 

當然強烈推薦你看下twitch.tv 這篇文章[4],相信讓你會對 GOGC 以及 ballast 的運用理解的更加透徹。

責任編輯:武曉燕 來源: HHFCodeRv
相關推薦

2021-07-14 13:46:28

KubeVela阿里云容器

2025-03-03 12:00:00

JavaScriptfor 循環語言

2025-04-18 08:24:22

2023-10-07 14:49:45

2021-01-18 18:42:33

工具調優開發

2025-06-05 02:25:00

2022-12-20 09:09:27

ViteWebpack

2020-07-22 15:15:28

Vue前端代碼

2025-03-10 08:44:17

2020-12-21 08:32:07

內存性能優化

2023-10-06 20:46:27

開發工具開發代碼

2025-06-04 08:35:00

立即執行函數IIFEJavaScript

2023-09-27 07:49:23

2023-09-13 16:34:47

Java工具開發

2022-09-05 13:16:42

MicroVim編輯器

2023-03-15 15:54:36

Java代碼

2022-08-28 10:08:53

前端代碼前端

2024-05-30 11:44:37

2022-03-18 13:59:46

緩存RedisCaffeine
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: wwwxxx日本在线观看 | 国产精品成人一区二区 | h在线观看 | 成人在线中文字幕 | 天天干 夜夜操 | 久久久久国产 | 国产精品高潮呻吟久久 | 国精日本亚洲欧州国产中文久久 | 亚洲传媒在线 | 一级大黄 | 欧美性jizz18性欧美 | 91成人在线| 操人网站 | 日本天天操| 四虎在线观看 | 成人午夜激情 | 国产精品99久久久久久久久久久久 | 99久久精品国产一区二区三区 | 精品国产99| 欧美男人天堂 | 日韩伦理一区二区 | 91国在线| 久久精品99 | 欧美极品少妇xxxxⅹ免费视频 | 精品久久香蕉国产线看观看亚洲 | 国产精品自拍视频 | 国产欧美一区二区三区久久人妖 | 亚洲欧美视频一区二区 | 亚洲日本三级 | 亚洲免费在线观看av | 天天欧美 | 免费一区| 欧美日韩成人网 | 欧美一区二区在线 | 欧美成人a| www.婷婷亚洲基地 | 色婷婷综合网 | 天天草天天干 | 日韩在线欧美 | 中文字幕一区二区三区四区五区 | 一区二区三区在线 |