go pprof火焰图快速分析cpu高负载问题

前言:

公司一个同事使用go websocket开发了k8s在线调试服务,该服务也部署在k8s集群中,没几天运维那边通告说 cpu 100% 高负载了,还把限制的范围内的cpu core都干满了。由于那人休假,我帮忙处理下。

通常来说这类cpu高负载的问题相对好排查,多是bug造成了。像这个调试服务在一个量级请求完毕后,cpu使用率居然还是爆满。😅 不用想直接,肯定是协程泄露了,造成了某个逻辑的忙轮询。

准备

该服务在k8s集群中部署,没有接入ingress,所以在有外网的k8s node上做了一个端口映射。这样开发机可go tool pprof外网地址。

还有一个好方法是我以前常用的,在k8s node上把golang的pprof可分析数据导入到文件里,然后把文件post到一个支持上传的服务,比如http upload。后面大家就知道该怎么操作了。

分析问题

下面是pprof生成的火焰图和调用链耗时图,很明显的看到writeLoop不断的调用Close()方法。

既然确定了问题,通过pprof source定位热点代码,可以看到为什么不断调用wsConn.Close()呢 ? 因为没有return,既然已感知连接关闭,那么就应该return出去 !!!

// xiaorui.cc

  Total:       2.31s   1.35mins (flat, cum) 99.25%
     76            .          .                } 
     77            .          .           } 
     78            .          .            
     79            .          .           // 发送协程 
     80            .          .           func (wsConn *WsConnection) wsWriteLoop() { 
     81        330ms      330ms                defer fmt.Println("write exited") 
     82            .          .                for { 
     83        740ms   1.05mins                        select { 
     84        720ms      730ms                        case msg = <-wsConn.outChan: 
     85            .          .                                if err = wsConn.socket.WriteMessage(msg.MessageType, msg.Data); err != nil { 
     86            .          .                                        log.Error("websocket write message error", err) 
     87            .          .                                } 
     88        220ms      220ms                        case <-wsConn.closeChan: 
     89        300ms     16.21s                                wsConn.Close() 
     90            .          .                        } 
     91            .          .                } 
     92            .          .           }

总结

相比性能调优,这类由于bug引起的cpu高负载问题反而特别处理,基本上通过pprof看火焰图就可快速定位问题。


大家觉得文章对你有些作用! 如果想赏钱,可以用微信扫描下面的二维码,感谢!
另外再次标注博客原地址  xiaorui.cc