Ticker 未释放导致的 CPU 占用过高
问题描述
2018-12-15, 辅导服务一台服务器的 TCP 连接数忽上忽下(如下图), 上下浮动在400~500的数量. 而此时 CPU 一直在满负载, 内存占用很高(如下图). 导致用户无法正常上课.
问题缘由
1. TCP 连接中, 存在全球各地的 IP, 并且数量占比很高, 存在恶意攻击的可能.
2. 辅导服务会为每个 TCP 连接都会创建一个 ticker, 并且没有释放. time.NewTicker() → time.startTimer() → runtime.addtimer() → runtime.addtimerLocked() → runtime.timerproc() → runtime.siftdownTimer().
每来一个 TCP 连接, ticker 会新增, timerproc 是唤醒处理定时器的一个函数. golang使用的最小堆维护的一个timer队列, go比较费时,每次操作最坏情况下都是logn(n为时间队列长度).
新建了很多 ticker, 资源未释放, 导致内存占用过高.
经验教训
Never call time.NewTicker(…) within a fast iterating for loop.
Stop the ticker to release associated resources.
参考资料:
https://zhuanlan.zhihu.com/p/30268582
https://guidao.github.io/go_timer.html
https://forum.golangbridge.org/t/runtime-siftdowntimer-consuming-60-of-the-cpu/3773