用go写了一个守护进程程序:用于检测redis的存活状态并将结果写到zookeeper中,部署到redis机器上,对于每个redis实例会有一个goroutine每隔固定时间去检测其状态,由主goroutine负责信号处理等,再接收到信号时kill其他的goroutine。程序运行了一段时间发现,有些redis实例的对应zookeeper的信息不更新,通过日志发现对应redis的goroutine挂掉了。阅读源码发现貌似是zk的第三方库抛出一个非预期的异常导致。
为了解决这个问题,对逻辑重构:由主goroutine每隔固定时间,对于每个redis实例启动一个goroutine去进行检测,避免出现非预期异常导致goroutine挂掉,从而状态信息不更新的情况。由于goroutine的创建开销很低,并且golang官方推荐使用大量的goroutine来抗并发,所以这种方式实现也很合理。重构完,上线测试发现存在内存泄露。
(1)观察GC
首先对代码review,因为半年前写的,并且最近都没用golang,所以没有发现bug。接着,就想看下gc相关的信息,也许可能透漏些东西。网上查了golang gc相关,在runtime的doc中描述了,通过设置环境变量GODEBUG='gctrace=1'可以让go的运行时把gc信息打印到stderr。
GODEBUG='gctrace=1' ./sentinel-agen