基本信息
文件名称:go语言程序cpu过高问题排查的方法详解.docx
文件大小:16.06 KB
总页数:3 页
更新时间:2025-05-20
总字数:约1.25千字
文档摘要

go语言程序cpu过高问题排查的方法详解

目录一、前言二、问题排查过程2.1通过top查看高cpu的进程pid2.2通过top查看高cpu的线程tid2.3通过dlv附加到进程,分析线程/协程cpu过载的堆栈2.4在dlv中切换到对应高cpu协程,并查看堆栈总结

一、前言

Go程序像C/C++一样,如果开发编码考虑不当,会出现cpu负载过高的性能问题。如果程序是线上环境或者特定场景下出现负载过高,问题不好复现,则需要利用当前负载过高的进程进行调用栈分析。

C/C++中一般先通过top-d1-p$pid-H命令查看负载过高的线程号(TID),然后使用gdbattach到该进程,通过threadinfo获取线程信息,然后切换到对应负载高的线程,输入bt查看调用栈。

结合对应代码中的函数,进一步分析。Go语言中方法也类似,我们将通过dlv来分析负载高的协程调用栈。

二、问题排查过程

2.1通过top查看高cpu的进程pid

通过top-d1,可以发现进程cava_smu(pid=11205)的cpu过高。

2.2通过top查看高cpu的线程tid

通过上一步,我们确定了是pid=11205的cava_smu进程cpu过高,那么可以通过top-d1-p11205-H来确认cpu过载的线程tid,如下图所示:

通过以上操作,可以确认tid=11208,11212,11213三个线程的cpu过高。

2.3通过dlv附加到进程,分析线程/协程cpu过载的堆栈

首先,如果生产环境没有dlv,则可以拷贝对应的dlv到/usr/local/bin下。

接着dlvattach11205,确认tid=11208的goroutine序号,如下图所示:

2.4在dlv中切换到对应高cpu协程,并查看堆栈

如下图所示:

通过以上操作,可以确认业务底层的栈帧是第65帧,business.go:18行的disPatchTask-business.go:168行的dispatchIdleTeu方法相关,查看对应版本代码如下:

代码执行到下图中,dispatchIdleTeu返回了错误qferror.ErrNoTeu。

代码执行到下图中,189行dispatchIdleTeu返回了错误qferror.ErrNoTeu,所以189if的执行语句192~212无法进入进行,而外层是一个for死循环,则会造成该协程一直占用cpu,导致cpu过载。

修复方法可以是在for循环内增加sleep休眠,例如在214行处增加time.Sleep(200*time.Millisecond),效果请自行验证。

总结