从真实事故出发:golang 内存问题排查指北

动手点关注 干货不迷路 👆

问题出现

出现报警!!!

在日常搬砖的某一天发现了某微服务 bytedance.xiaoming 服务有一些实例内存过高,达到 80%。而这个服务很久没有上线过新版本,所以可以排除新代码上线引入的问题。

390c66128ce72e5153f6420b287d4238.png

发现问题后,首先进行了迁移实例,除一台实例留作问题排查外,其余实例进行了迁移,迁移过后新实例内存较低。但发现随着时间推移,迁移过的实例内存也有缓慢增高的现象,有内存泄漏的表现。

问题定位

推测一:怀疑是 goroutine 逃逸

排查过程

通常内存泄露的主因就是 goroutine 过多,因此首先怀疑 goroutine 是否有问题,去看了 goroutine 发现很正常,总量较低且没有持续增长现象。(当时忘记截图了,后来补了一张图,但是 goroutine 数量一直是没有变化的)

ce96f2c1f74bfe6c20f160f8c5ab0b92.png
排查结果

没有 goroutine 逃逸问题。

推测二:怀疑代码出现了内存泄露

排查过程

通过 pprof 进行实时内存采集,对比问题实例和正常实例的内存使用状况:

问题实例:

4f4ca0ce7f5aeea8df879f6e1a92d5d8.png

正常实例:

4a9476904d15e4e787058a53dbfd43f1.png

进一步看问题实例的 graph:

476e24e854bbd34d6ed5557f80ca4077.png

从中可以发现,metircs.flushClients()占用的内存是最多的,去定位源码:

func (c *tagCache) Set(key []byte, tt *cachedTags) {
        if atomic.AddUint64(&c.setn, 1)&0x3fff == 0 {
                // every 0x3fff times call, we clear the map for memory leak issue
                // there is no reason to have so many tags
                // FIXME: sync.Map don't have Len method and `setn` may not equal to the len in concurrency env
                samples := make([]interface{}, 0, 3)
                c.m.Range(func(key interface{}, value interface{}) bool {
                        c.m.Delete(key)
                        if len(samples) < cap(samples) {
                                samples = append(samples, key)
                        }
                        return true
                }) // clear map
                logfunc("[ERROR] gopkg/metrics: too many tags. samples: %v", samples)
        }
        c.m.Store(string(key), tt)

}

发现里面为了规避内存泄露,已经通过计数的方式,定数清理掉 sync.Map 存储的 key 了。理论上不应该出现问题。

排查结果

没有代码 bug 导致内存泄露的问题。

推测三:怀疑是 RSS 的问题

排查过程

这时注意到了一个事情,在

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值