1. 问题发现过程
当cpu过高的时候,服务器在执行命令的时候会出现卡顿的现象。
通过linux的top命令查看了cpu使用率最高的进程,发现了异常的程序
2. 问题解决过程
本来想通过go tool pprof来定位出问题的代码在哪里, 通过访问服务端暴露的
pprof的接口得到对应的profile文件,然后利用火焰图分析代码中当前使用cpu最高的代码块。
但是因为代码中并不包含pprof的那些接口,所以只能通过其他方法去解决问题。
通过pstack只能看到c程序的堆栈,这条路基本走不通。
想通过perf top 和perf report来查看堆栈也只能看到C的堆栈,看不到go的堆栈。
通过strace -p pid定位到包含了大量的write语句,发现了在写日志文件
所以通过tail命令查看日志文件,发现一直在打印某一行日志。
其中日志错误显示为:
stream recv error:rpc error:code Unavailable desc = error reading from server: EOF
在代码中查询打印的日志内容,发现了出现问题的代码块。
for{
// some code
msg, err := stream.Recv()
ctx := trace.NewTrace(msg.GetMsgId(), "xxxxxx")
if err != nil {
log.Error(ctx, fmt.Sprintf("stream recv error:%v", err))
continue
}
//other code
}
因为rpc的网络连接断开,导致这里的stream.Recv一直在报错,而由于代码中出错的之后
处理的方法逻辑是continue,然后外部是for循环,就会一直重复的打印出错日志
最终导致cpu过高,因为一直在死循环。
解决方法:
把这里的continue改成return语句,如果出错直接返回就行了,这样连接中断stream不会一直在死循环中读取连接中的内容。