go 定时器泄漏,导致 CPU占用高

问题

服务器长期开着,遇到一个问题,没有几个有效负载,CPU 占用了 2 个核

go tool pprof 了下,大致如下调用消耗:

go 定时器泄漏,导致 CPU占用高_第1张图片

top100 ,显示 runtime.siftdownTimer 占了大头(2 个图,取至不同服务)

go 定时器泄漏,导致 CPU占用高_第2张图片

问题分析

可以看到,均为定时器相关代码调用

review 代码,不少定时器用完没有 Stop 释放

模拟做下类似情景性能测试:

1. 创建 2w 个 timer + 1 个 timer 在工作:
go 定时器泄漏,导致 CPU占用高_第3张图片

如图,CPU 占用了 61.5%

2. 只有 1 个 timer 在工作
go 定时器泄漏,导致 CPU占用高_第4张图片
看不到 CPU 消耗

因此可以得出结论:定时器泄漏,会导致 CPU 占用高

为什么会消耗 CPU

参考 https://www.cnblogs.com/Zereker/p/11396639.html

该作者分析的很透彻了

再做个试验

把泄漏的定时器,时间间隔改大到秒级别。单个定时器工作时,CPU也不会上去
go 定时器泄漏,导致 CPU占用高_第5张图片
因此,要避免同时存在大量毫秒级别的定时器,golang 底层需要维护优先队列数据结构会消耗大量 CPU

因为最坏的操作,每次维护优先队列数据结构都是 O(LogN) 的时间复杂度。而大量毫秒级别的定时器会把时间复杂度拉到最坏情况 O(M*LogN)

golang 定时器问题总汇

到目前为止,至少遇到 3 处 golang 定时器问题,及解决方案:

定时器问题 解决方案
定时器泄漏 避免内存泄漏,比如可以封装 timer ,引用计数,随意可以查看定时器对象数量等
同时刻存在大量毫秒级定时器 业务上要避免这种情况的代码,没有通用解决方案
session 级别秒级定时器 业务上做到被动触发,来规避该问题

参考

  • https://forum.golangbridge.org/t/runtime-siftdowntimer-consuming-60-of-the-cpu/3773
  • https://www.cnblogs.com/Zereker/p/11396639.html

你可能感兴趣的:(Go语言杂文,golang,ticker,CPU占用高,内存泄漏,性能分析)