go程序cpu过高问题排查方法

目录

一、前言

二、问题排查过程

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

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

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

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


一、前言

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

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

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

二、问题排查过程

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

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

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

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

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

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

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

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

 

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

如下图所示:

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

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

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

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值