我使用 Golang 写的一个融合日志服务, 定时融合不同云厂商的日志, 该服务部署在 K8S 上.
在国庆期间日志量倍增, 该服务频繁被 Killed.
通过仪表盘, 发现该服务运行一次后, 内存不会释放, 怀疑是内存泄露导致的. 见下图.
最终, 我通过使用 pprof 解决了该问题.
1. 开启 pprof 服务
pprof 是 Golang 自带的性能分析工具. 可以 2 步 开启 pprof 服务.
// 1. 引入 net/http/pprof 包
_ import "net/http/pprof"
// 2. 开启 http 服务
go http.ListenAndServe(":9999", nil)
2. 通过 pprof 的 Web 页面分析 goroutine
[]()
如图:
full goroutine stack dump
goroutine
我在 Web 页面上并未发现有价值的信息, 于是使用命令行分析.
3. 通过 pprof 的命令行分析 heap
go tool pprof -inuse_space []()
这个命令的作用是, 抓取当前程序已使用的 heap. 抓取后, 就可以进行类似于 gdb 的交互操作.
time.NewTimer
list <函数名>list time.NewTimerNewTimerruntimeTimer
for ... select ... time.After
原来程序中存在如下代码:
for {
select {
case a := <-chanA:
...
case b := <-chanB:
....
case <-time.After(20*time.Minutes):
return nil, errors.New("download timeout")
}
time.AfterNewTimertime.After
func After(d Duration) <-chan Time {
return NewTimer(d).C
}
NewTimer
downloadTimeout := time.NewTimer(20 * time.Minute)
defer downloadTimeout.Stop()
for {
select {
case a := <-chanA:
...
case b := <-chanB:
....
case <-downloadTimeout.C:
return nil, errors.New("download timeout")
}