前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >新部署的服务 go_cpu 占满如何处理?

新部署的服务 go_cpu 占满如何处理?

作者头像
腾讯云可观测平台
发布2021-10-22 09:40:08
6970
发布2021-10-22 09:40:08
举报

作者:周易建,腾讯云云监控高级工程师

排查结果展示

[点击查看大图]

故障现象

新部署的服务,没有任何请求。但 Pod 上的 CPU 一直是占满状态,但是查看现网服务未发现问题。

定位问题

1. 先埋点,看耗时卡在哪个环节。

从前端调用接口,到中间检测环节,再到下游某服务环节,发现调用耗时都在该业务服务上。

再看日志,一个新增数据库的接口请求耗时竟然要 1s,再其它两个接口,从请求到完成耗时也要 1-2s。说明该业务服务明显出现了问题。

2. 模块问题已确定,现需定位追踪调用的接口问题。

因为是在新的地域,部署一套新的服务,代码是直接在现网服务的分支上,仅仅是直接重新打包了一个镜像,没有改动代码,因此初步排查代码没有问题。

在代码里加日志,追踪这个接口的每个函数耗时,发现每个 SQL 请求都要耗时 100+ms。

[点击查看大图]

3. 排查是否是 MySQL 的问题。

排查是代码的 SQL 连接池有问题?还是 MySQL 有问题。

但是代码跟现网一致,不可能是 SQL 连接池的问题。再排查发现没有慢查询,更换 MySQL 实例后未发现异常,说明也不是 MySQL 的问题。

4.排查是否是服务连接 MySQL 的问题。

我们该如何测试服务连接 MySQL 的问题?在 pod 上,按照 MySQL 客户端连接并执行 SQL语句即可。

安装并连接 Centos mysql client,使用 show profile 来查看 SQL 执行情况,发现在 pod 上执行 SQL 也是正常的,仅是毫秒级别。

代码语言:javascript
复制
// centos 使用yum安装mysql 客户端yum install mysql-community-client.x86_64 -y
// 登上mysql clientmysql -h ip -u root -p
// 打开profile 开关show variables like "%prof%”set profiling = 1; // 0是off,1是on
// 查看语句执行情况select count(*) from c_consumer;show profiles;
set profiling = 0;

[点击查看大图]

[点击查看大图]

在 pod 上连接 MySQL 执行没问题。但是服务运行时,日志就是这里耗时久。究竟是什么原因呢?

4.排查是否是服务自身问题。

排查 MySQL 未发现问题,pod 连接 MySQL 未发现问题。说明也不是网络的问题。

我们再打开 pod 监控视图,发现 CPU 占满了。

[点击查看大图]

新部署的服务,没有任何请求,CPU 占用应该是 0%,为什么会占满呢?

接下来我们将要拿出最后的排查,进行 pprof 分析。

pprof  分析

pprof 分析前提:代码中使用了 pprof。

1.  导入  'net/http/pprof ',并运行  'http server '。

代码语言:javascript
复制
// 导包import _ "net/http/pprof”// 服务启动的时候,在main函数中,另起一个 goroutines 跑一下 http servergo func() {   if err := agent.Listen(agent.Options{Addr: "0.0.0.0:6061"}); err != nil {      log.Println(err)   }}()

2. 使用下列两种方式查看 pprof 分析结果。

a. 应用中使用 pprof 中后,使用  ip:port 进入网址查看分析结果。

代码语言:javascript
复制
// 这里使用了tke部署,采用的是service ip + port访问,实际映射的是容器内的pprof监听端口 6061
http://9.145.241.216:8080/debug/pprof/

如图:

[点击查看大图]

b. 使用命令行查看分析结果。

代码语言:javascript
复制
1. 查看堆栈调用信息go tool pprof http://9.xxx:8080/debug/pprof/heap
2. 查看 60 秒内的 CPU 信息go tool pprof http://9.xxx:8080/debug/pprof/profile?seconds=60
3. 查看 goroutine 阻塞go tool pprof http://9.xxx:8080/debug/pprof/block
4. 收集 5 秒内的执行路径go tool pprof http://9.xxx:8080/debug/pprof/trace?seconds=5
5. 争用互斥持有者的堆栈跟踪go tool pprof http://9.xxx:8080/debug/pprof/mutex

排查 CPU 占满问题

1. 查看完分析结果后,登录 IDC 环境,执行命令,得到相关日志文件。

代码语言:javascript
复制
go tool pprof http://9.xxx:8080/debug/pprof/profile?seconds=60

[点击查看大图]

2. 将文件传到本机,查看图形化界面。

代码语言:javascript
复制
// IDCmv /root/pprof/pprof.amp_for_cloud.samples.cpu.004.pb.gz .sz pprof.amp_for_cloud.samples.cpu.004.pb.gz// 本机cd Desktop/go tool pprof -http=:8081 pprof.amp_for_cloud.samples.cpu.001.pb.gz

[点击查看大图]

3、这时候就会自动弹出 Web 页面,您也可以手动进入`http://localhost:8080/ui/`

注意:mac 上面还需要安装图形化的界面工具:Graphviz 和 brew install graphviz。否则会提示:“Failed to execute dot. Is Graphviz installed? Error: exec: "dot": executable file not found in $PATH”。

3、在页面中找到下列代码块:

代码语言:javascript
复制
func init() {   tasks = make(chan *model.AlertMessage, taskLoad)   for consumbertIndex := 0; consumbertIndex < consumerCount; consumbertIndex++ {      go consumerUpdateSameAlarmStatusTask()   }}
var updateSameAlarmStatusProducingQuit = false
func Quit() {   updateSameAlarmStatusProducingQuit = true}
// 生产者func ProductTask(msg *model.AlertMessage) {    select {    case tasks <- msg:    default:        _metricEsUpdateErrorReqTotal.Inc(msg.ProductName)        Log.Errorf("ProductSaveDAlarmDataTaskTask task is full,donot write channel")    }}
// 消费者// pprof分析的重点代码模块func consumerTask() {   defer PostProcessingConsumerTaskHandler()   for {      select {      case msg := <-tasks:         saveDAlarmData(msg)      default:
         if saveDAlarmDataProducingQuit {            return         }      }   }}

发现这里利用 go channel 的特性,在服务内部开了一个生产/消费模型,上游请求过来的时候,会往 channel 里塞一个任务,在初始化的时候,起一个消费者不停的在消费该 channel,达到消息队列的效果,逻辑上看并没有什么问题,还需要进行深层的分析。

分析过程

根据代码块进行分析:

1. 无限 for 循环,满足 CPU 占满的条件了。

2. 函数简单,`saveDAlarmData` 里仅有 post 请求和存一下数据库操作,排除函数问题。

3. 会是 default 的问题吗?

select 机制是满足多个 case 的时候,随机选择一个,一个都没有的时候执行 default 。

在上述带代码的 default 中,只有一个判断项,而且这个一直是 false,未见 true 的条件,所以一直没有 return ,导致 CPU 一直卡在 default 中,无法出去。

解决方法

方法一:可以增加 time.sleep(),但使用方法二更为合适。

方法二:直接删掉 default 部分,就算阻塞,也是阻塞在一个 go routinue 里,不会阻塞主流程。

[点击查看大图]

总结

作为开发人员,尤其是对外服务的后台开发,快速定位并解决问题的能力很重要,由于软件、硬件甚至是环境等各种因素,服务故障时有发生,重要的是,如何在故障的时候,最快时间、最小成本的解决问题。

在发生 CPU、内存等这种非业务问题时,首先想的不是去寻找根因,而是保障服务稳定,本文是因为在新部署服务的时候发现的问题,不会影响客户,所以可以直接进行根因定位,如果是现网服务,要以客户为首,可以先用堆资源等手段缓解问题,然后再来排查问题所在。

日常工作中,要有一颗发现问题的心,遇到问题时,思路要清晰,通过工具、日志、自监控等途径,定位到是哪个进程、线程、函数导致该问题,解决问题时,要综合评估对业务、架构、性能的影响,永远保持对技术的探索精神和对线上服务的敬畏之心!

参考链接

Pprof 使用:https://www.jianshu.com/p/d97b095cd98a

Mac 安装 Graphviz:https://blog.csdn.net/qq_36847641/article/details/78224910

联系我们

若有任何问题可扫码联系云监控小助手,我们将竭诚为您服务!

点击下列阅读原文了解云监控。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-10-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 腾讯云可观测 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档