golang 高负载问题(二)空转

原创
2022/06/10 10:28
阅读数 604

我们的游戏还没有进入大推阶段,实时在线用户仅 200 左右,但是线上高性能服务器的 cpu 可以达到 8%,且偶现提升到 20%,单核跑满。此时服务器处理任务的效率受到影响,部分玩家在登录时心跳包超时,需要重连才能登录游戏。

通过对线上服务采集 pprof,我们发现大部分 cpu 时间都在处理一些 golang 底层逻辑,令人诧异。我们一度认为是自己使用 pprof 的姿势有问题,但是通过对 pprof 包引用进行验证后,并没有什么异常。

实际上,selectnbrecv 对应的 go 代码是 select default

上述代码的意图是,如果有待处理的任务,判断是否有新的任务,如果有,对它进行处理,否则不进行处理;如果没有待处理的任务,阻塞 goroutine,等待新任务。这段代码在处在一个for循环中。

逻辑上考虑,上述代码似乎没有什么问题,但它却是导致 cpu 负载异常的直接原因。我们知道,一个 空的for循环,会跑满单核 cpu。那么在没有新的任务到来的时候并且存在待处理任务时,上述代码实际上没有任何阻塞,处在一个空转的状态。

我们写一些测试代码可以模拟这个状态:

到此,我们认为这个有序队列是不可用的,长远考虑下替换一个新的队列实现才是正道。

新的队列将轮询的操作下放给用户,不再有select default。这样自然也不会有空转的问题。

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部