关于 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。

func main() {ballast := make([]byte, 10*1024*1024*1024) // 10G // do somethingruntime.KeepAlive(ballast)
}

上面的代码就初始化了一个 ballast,利用 runtime.KeepAlive 来保证 ballast 不会被 GC 给回收掉。

利用这个特性,就能保证 GC 在 10G 的一倍时才能被触发,这样就能够比较精准控制 GO GC 的触发时机。

这里你可能有一个疑问,这里初始化一个 10G 的数组,不就占用了 10 G 的物理内存呢? 答案其实是不会的。

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    VSZ
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 = 50G

这张图相同的流量压力下,ballast 的表现明显偏好

结论

本篇文章只是简单的阐述了 Go ballast 的使用,Go ballast 是官方比较认可的方案,具体可以参见 issue 23044[1]。很多开源程序,如 tidb[2],cortex[3] 都实现了 go ballast,如果你的程序饱受 GOGC 的问题影响或者周期性的耗时不稳定,不妨尝试下 go ballast。

当然强烈推荐你看下twitch.tv 这篇文章[4],相信让你会对 GOGC 以及 ballast 的运用理解的更加透彻。

写文章不易请大家帮忙点击 在看,点赞,分享。

参考资料

[1]

issue 23044: https://github.com/golang/go/issues/23044

[2]

tidb: https://github.com/pingcap/tidb/pull/29121/files

[3]

cortex: https://github.com/cortexproject/cortex/blob/master/cmd/cortex/main.go#L148

[4]

twitch.tv 这篇文章: https://blog.twitch.tv/en/2019/04/10/go-memory-ballast-how-i-learnt-to-stop-worrying-and-love-the-heap/

Ballast,一种精准控制 Go GC 提高性能的方法相关推荐

  1. [css] 列举CSS优化、提高性能的方法

    [css] 列举CSS优化.提高性能的方法 加载性能压缩CSS通过link方式加载,而不是@import复合属性其实分开写,执行效率更高,因为CSS最终也还是要去解析如 margin-left: le ...

  2. 计算机性能过低配色方案,系统之家windows7提示更改配色方案提高性能的方法

    有很多win7旗舰版用户在运行一些游戏的时候弹出了是否要更改配色方案来提高性能的提示,原因是检测到计算机性能过低的问题,其实可以选择使用更低内存的windows7 basic主题或者提高虚拟内存,下面 ...

  3. 21. CSS 优化和提高性能的方法有哪些?

    21. CSS 优化和提高性能的方法有哪些? 加载性能 css 压缩, 将写好的 css 进行打包压缩, 可以减小文件体积 css 单一样式, 当需要下边距和左边距的时候, 很多时候会选择使用 mar ...

  4. css面试题(7)CSS优化、提高性能的方法有哪些?

    CSS优化.提高性能的方法有哪些? 避免过度约束 过渡约束的代码: div{position:relative;bottom:100px; // 不必要的样式约束top:-200px;width: 2 ...

  5. 【前端知识之CSS】CSS提高性能的方法有哪些

    前言 本系列主要整理前端面试中需要掌握的知识点.本节介绍如果要进行优化,CSS提高性能的方法有哪些. 文章目录 前言 一.内联首屏关键CSS 二.异步加载CSS 三.资源压缩 四.合理使用选择器 五. ...

  6. CSS 优化、提高性能的方法

    如何提高CSS性能,根据页面的加载性能和CSS代码性能,主要总结有下面几点: 1.尽量将样式写在单独的css文件里面,在head元素中引用 有时候为了图方便或者快速搞定功能,我们可能会直接将样式写在页 ...

  7. 8种提升ASP.NET Web API性能的方法

    英文原文:8 ways to improve ASP.NET Web API performance ASP.NET Web API 是非常棒的技术.编写 Web API 十分容易,以致于很多开发者没 ...

  8. Mysql中“饮鸠止渴“提高性能的方法(临时性提升)

    该文章为<MySQL实战45讲>课程学习笔记及部分摘抄,原课程链接MySQL 实战 45 讲 (geekbang.org) 不知道你在实际运维过程中有没有碰到这样的情景:业务高峰期,生产环 ...

  9. CSS 优化、提高性能的方法有哪些?

    一.写在前面 css的优化方案,之前没有提及,所以接下来进行总结一下. 二.具体优化方案 2.1.加载性能 1.css压缩:将写好的css进行打包,可以减少很多的体积. 2.css单一样式:在需要下边 ...

最新文章

  1. mysql 8.0免安装配置_Mysql8.0免安装包配置方法
  2. 使用HTML完成简历
  3. Method Area(方法区)
  4. MAUI安卓子系统调试方法(附安装教程)
  5. mysql 聚簇索引和非聚簇索引_图文并茂,说说MySQL索引
  6. Windows+VS2013爆详细Caffe编译安装教程
  7. ActiveMQ反序列化漏洞(CVE-2015-5254)复现
  8. 从源码角度看Spark on yarn client cluster模式的本质区别
  9. 使用 Moq 测试.NET Core 应用 -- Mock 方法
  10. 【华为大咖分享】7.大型云平台的DevOps实践(后附PPT下载地址)
  11. 实现 消息提醒图标_Mac 上自带的「提醒事项」千万别错过
  12. php给网页加水印_php实现给一张图片加上水印效果
  13. ffmpeg将h264和aac合成ts,内存输入输出
  14. 王飞跃谈正来临的第五次工业革命:“未来一定有多个平行的你”
  15. java 句柄无效_Java开发网 - java.io.IOException: 句柄无效???
  16. 爬取王者荣耀皮肤-点券领取
  17. html+css实现一个会旋转且变大的静态照片墙
  18. 云笔记有哪些好用的功能,这4款云笔记一定要试试
  19. Eclipse在导入项目时显示 “Invalid Project Description”时的处理方法
  20. linux常见的解压命令,linux常见解压命令

热门文章

  1. 【译】区块链是如何工作的——用JavaScript演示
  2. 使用Spring配合Junit进行单元测试的总结
  3. 被除数、除数、商、余数的正负号规律二
  4. mongo系统(1)
  5. vnc报错 font catalog is not properly configured
  6. 黄聪:Python中的__metaclass__=type什么意思?
  7. subsonic 配置及使用
  8. 组态软件开发(zz)
  9. 改2003远程端口3389的方法!
  10. APAC SharePoint Conference 2007 讲义与资源下载