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
相关推荐
海盗12347 分钟前
DSH 接入 OpenCode Go 报 400 MissingSessionID:从 LLM 语义层退到 fetch 传输层的完整排障
开发语言·后端·golang
weixin1997010801613 分钟前
《Mercari OTA 直连接入:日本二手电商出海的API通道与600次/分钟限流实战》(附Python源码)
开发语言·数据库·python
一木 之林16 分钟前
第 3 节 在 AI 行业中,C/C++ 编程中的动态库和静态库
c语言·c++·后端
库玛西17 分钟前
深度解构高并发利器:纯事件驱动 Reactor 模式的设计哲学与工程实践
服务器·开发语言·c++·笔记·tcp/ip
skywalkerch22 分钟前
Spring 循环依赖与三级缓存
后端
lemon_sjdk28 分钟前
JavaScript 常用关键字全解析
开发语言·javascript·ecmascript
linx29531 分钟前
单元五 · 对称认知·下:编译与链接
linux·c语言·开发语言·c++·嵌入式硬件
萧瑟余晖43 分钟前
Hibernate 实体映射与关联关系详解
后端·hibernate
2501_930472441 小时前
从物理机到 CVM 全流程落地:部署脚本的 8 个云化改造点(附代码对比)
开发语言·人工智能·架构·腾讯云·perl
stars3691 小时前
实验四 JSP内置对象的应用
后端