go 内存泄露

事件回顾

  • 9.15号晚18点服务端发版
  • 9.16号晚21点监控显示自发版后服务器 TCP_alloc 指标一路飙升至40K(如图)

问题分析

看到 tcp_alloc 指标异常,初步怀疑有tcp连接创建后未关闭,应该是上次发版写了什么代码导致的。回顾此次发版清单,问题应该出现在了daemon服务心跳上报上。

daemon服务是一个业务监控服务,通过监听etcd中注册的服务状态变更,向企业微信用户发送消息提醒。在此之前由于消息提醒协程panic异常退出,导致Ad服务停止后消息提醒未正常发出,造成生产P3事故。本次发版通过增加每3秒心跳保活机制,双重保证在服务中断后,消息提醒能正常发出(代码如下)

复制代码
func KeepAliveWithMp() {
	var keepAliveWithMpUrl, _ = config.String("keepAliveWithMpUrl")
	if keepAliveWithMpUrl == "" {
		return
	}
	ticker := time.NewTicker(3 * time.Second)
	for range ticker.C {
		_, _ = http.Get(keepAliveWithMpUrl + "?runningKey=" + getRunningKey())
	}
	ticker.Stop()
}

问题出现在了 http.Get 请求发出后未读取响应主体,也没有关闭此次tcp连接,导致一直在创建新的tcp连接,一个get请求会创建两个goroutine,导致内存泄露。

此处有两种修复方式,一是在http请求完了之后主动关闭此次连接释放资源,另一种则是读取响应主体后复用改链接

代码修复

复制代码
// 方式一
func KeepAliveWithMp() {
	var keepAliveWithMpUrl, _ = config.String("keepAliveWithMpUrl")
	if keepAliveWithMpUrl == "" {
		return
	}
	ticker := time.NewTicker(3 * time.Second)
	for range ticker.C {
		resp, _ := http.Get(keepAliveWithMpUrl + "?runningKey=" + getRunningKey())
		_ = resp.Body.Close()
	}
	ticker.Stop()
}


// 方式二
func KeepAliveWithMp() {
	var keepAliveWithMpUrl, _ = config.String("keepAliveWithMpUrl")
	if keepAliveWithMpUrl == "" {
		return
	}
	ticker := time.NewTicker(3 * time.Second)
	for range ticker.C {
		resp, _ := http.Get(keepAliveWithMpUrl + "?runningKey=" + getRunningKey())
		_,_ = ioutil.ReadAll(resp.Body)
	}
	ticker.Stop()
}

后期预警

通过每小时检测一次服务器 TCP_alloc 指标,当超过30K 后发送短信提醒,避免再次出现该异常。

复制代码
// TCP_alloc 指标查看方式
cat /proc/net/sockstat 

sockets: used 3621
TCP: inuse 2833 orphan 5 tw 1792 alloc 3354 mem 489
UDP: inuse 9 mem 4
UDPLITE: inuse 0
RAW: inuse 0
FRAG: inuse 0 memory 0
相关推荐
bcbnb6 分钟前
iOS 性能测试的工程化方法,构建从底层诊断到真机监控的多工具测试体系
后端
foxsen_xia7 分钟前
Go安装、配置和vsCode配置Go
开发语言·vscode·golang
雍凉明月夜8 分钟前
c++ 精学笔记记录Ⅰ
开发语言·c++·笔记
开心就好20259 分钟前
iOS 上架 TestFlight 的真实流程复盘 从构建、上传到审核的团队协作方式
后端
小鹏编程14 分钟前
C++ 周期问题 - 计算n天后星期几
开发语言·c++
繁华似锦respect14 分钟前
C++ unordered_map 底层实现与详细使用指南
linux·开发语言·c++·网络协议·设计模式·哈希算法·散列表
小周在成长18 分钟前
Java 泛型支持的类型
后端
aiopencode18 分钟前
Charles 抓不到包怎么办?HTTPS 抓包失败、TCP 数据流异常与底层补抓方案全解析
后端
太阳以西阿18 分钟前
【计算机图形学】01 OpenGL+Qt
开发语言·qt
稚辉君.MCA_P8_Java23 分钟前
Gemini永久会员 C++返回最长有效子串长度
开发语言·数据结构·c++·后端·算法