问题

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

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

在这里插入图片描述

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

在这里插入图片描述

问题分析

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

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

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

1. 创建 2w 个 timer + 1 个 timer 在工作:
在这里插入图片描述

如图,CPU 占用了 61.5%

2. 只有 1 个 timer 在工作
在这里插入图片描述
看不到 CPU 消耗

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

为什么会消耗 CPU

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

该作者分析的很透彻了

再做个试验

把泄漏的定时器,时间间隔改大到秒级别。单个定时器工作时,CPU也不会上去
在这里插入图片描述
因此,要避免同时存在大量毫秒级别的定时器,golang 底层需要维护优先队列数据结构会消耗大量 CPU

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

golang 定时器问题总汇

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

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

参考

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐