之前用Go写的agent , 在持续运行一个多月后,发现agent本身的cpu 使用率会一直爬高,也就是存在cpu泄漏的问题。
开始初步锁定范围是我们的一个ping 的采集出了问题, 这个ping 我们是修改了fastping的库来做ping的发送,但是自查了一遍修改的代码,没发现问题。于是用pprof 抓取cpu 使用率, 发现有大量的runtime.futex 这种syscall 和runtime的shiftdownTimer。如下图:
这里推测应该是某处timer 的使用有问题,于是再次翻看修改的fastping库,才发现在每次会创建的goroutine 当中会创建一个NewTicker 来处理timeout ,但是这个NewTicker 在timeout后,又没有Stop. 所以每次采集的时候都会创建新的NewTicker,导致futex 越来越多,导致cpu 泄漏。
类似于以下代码, 在不断的开启goroutine,但是没有在for {} 结束以后,调用timeout.Stop()
go recv()
func recv() {
timeout := time.NewTicker(1 * time.Second)
for {
select {
case <- xx:
dosth()
case <- timeout:
dosth2()
}
}
}
这里有几个问题:
一、在这种一次性处理timeout 的情况下,是否用time.After或者其它方式更好?
二、不同的timer函数在不同的场景下是否有比较好的使用方式呢?
当然golang 本身的timer可能不满足特定的场景,要另外构建自己的timer,那是另外一回事啦。