记一次goroutine泄漏的问题

本文讲述了Golang中由于goroutine泄漏导致的内存占用过高问题。问题源自一个程序,该程序在接收到心跳包后,若无数据库配置,则无法通过channel正确处理数据,导致channel阻塞并积累大量goroutine。修复方案是在发送端添加判断,避免向未配置的channel发送数据。
摘要由CSDN通过智能技术生成

Golang因为有着比线程更加轻量级的协程的出现,使得并发编程的上手难度一下子变得亲民起来。而channel的引入,使得goroutine之间的通信变得异常的便捷。SOFMGUEBMWIDREWO
但好用并不意味着毫无风险,go channel使用不当,也极易引起goroutine泄漏。
何谓goroutine泄漏?就是开启了goroutine,却并没有及时回收,导致goroutine越积越多,如果程序及时关闭还不会出现问题,如果是在服务器中,程序长期运行,就会导致资源占用十分恐怖。
虽然goroutine比线程更轻量级,但每个goroutine至少也会有8~10K的空间,如果goroutine达到了一个恐怖的量级,内存的占用也是十分可怕的。
笔者近期就遇到了一个生产环境的goroutine泄漏问题。

问题复盘
我们有一套go语言开发的程序部署在客户的机器,该程序主要用来接收http请求,并将相应的请求解释成客户端配置文件,下发给客户端。服务器与客户端之间采用的是TCP长连接,二者之间靠心跳机制保活。
除此之外,该服务器还会接收客户端发过来的自监控性能指标信息,通过写ES或其他数据库的方式落到硬盘,以供监控分析。
以上这是背景。
起因是发现其中某一台机器上,该程序运行一段时间后,内存占用达到了数个G,而客户端的连接数量其实并不多。

image.png

通过pprof查看,发现goroutine的数量多得很不正常,甚至达到了13万多个。

image.png
用pprof工具定位,最终发现了问题所在,就是因为goroutine泄漏了。
那么,goroutine怎么会泄漏呢?经过分析代码终于发现了端倪,原来问题出在自监控信息上。
为了接受客户端自监控性能指标的信息,我们在服务器的配置文件中配置了数据库信息,如ES、MySQL、InfluxDb等,客户可以根据自己的需要选择合适的数据库进行存储。自监控信息通过心跳包携带上来。
在设计上是这么做的:心跳接受自监控信息和写数据库分别位于两个协程中,彼此之间通过channel通信。
channel的定义如下,它有1000个缓存:

Runner{
input: make(chan ProcessMetric, 1000),
config: config,
exporters: make(map[string]Exporter, 0),
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值