一个Go服务占用CPU太高的优化过程

最近上线一个Go服务, 在高峰期总是会报CPU超70%的报警.
然后就打开 pprof 开始追踪, 发现近 50% 的CPU被 runtime.gcDrain 及相关的 gc 函数占用了.

这说明 gc 很活跃.

这时候也不知道从哪里入手. 大概只有两个方向, 看一下 heap 的情况:

  1. 看看哪里占的内存总多
  2. 看看哪里分配的对象最多

最后定位到解码的函数, json 和 mapstructure.
仔细看了之后, 发现这里有很多直接传值的地方, 而不是传指针. 修改后, 再压测: 有改善, 但不明显.

这个时候就没有什么思路了.

经同事提醒. 再优化 elasticsearch 取数据的地方, 只取需要的 fields. 再压测, 发现有小幅提升. 但仍不明显.
跟同事讨论的时候, 我发现问题并不是CPU占用太高了, 而是CPU占用很高, 内存占用很少, 很不均衡. CPU占用70%, 内存不超过5%.

那搜索一下, 发现 Go 提供了一个 GOGC 的变量, 可以设置触发 GC 的值. 运行时也可以通过 runtime/debug 包的 func SetGCPercent(percent int) int 来修改.
默认是100, 那先修改成 500 看一下. 发现效果明显. CPU 降低了 50%.

问题解决了!!! 优化了一个星期, 改了很多代码. 最后是一行代码解决了!!!

不过目前看来 500 也有点低, 下次再调一下找一个更合理的值.

所以这个问题的原因是: 我们这个服务不是个CPU密集型的应用, 但是CPU占用过高, 而内存占用很低. (嗯, 只能说 Go 的 GC 很给力).
那这种情况下, 应该先看看, 是否可以降低触发 Gc 的阈值看一下, 也许就是你要的.