尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

记录一次线上服务OOM排查

记录一次线上服务OOM排查
📅 发布时间:2026/7/2 21:03:50

下午两点新版本上线,其中一个消费者服务的内存增长速度异常迅速,在短短五分钟内就用完了2G内存并自动重启了pod,之后又在五分钟内OOM了,在四十分钟内服务的pod已经重启了八十几次,要知道我们之前这个消费者服务正常运行时候只用了不到500M。

分析

首先进行初步分析,这是一个消费者服务并且新版本的需求中并没有新增消费topic,并且业务量也没有大的波动,不存在是业务访问量骤增导致OOM,所以极大概率会是代码问题。当然,每一个版本的新代码都非常多,需求也比较庞杂,直接去看代码肯定是不行的,这时候就要麻烦部门的运维大佬了,让他给我们dump一下,给出一个内存溢出时的性能记录文件,通过这个文件可以分析内存分配、线程创建、CPU使用、阻塞、程序详细跟踪信息等。

我这里使用的Go语言开发,一般用pprof文件进行分析,运维给出的文件有以下6个:

  • main-1-trace-1227152939.pprof:记录程序执行的详细跟踪信息,包括函数调用、Goroutine 的创建和调度等
  • main-1-threadcreate-1227152939.pprof:记录线程创建的剖析数据,帮助分析线程创建的频率和开销。
  • main-1-mutex-1227152939.pprof:记录互斥锁(mutex)的使用情况,帮助分析锁竞争和锁等待的开销。
  • main-1-mem-1227152939.pprof:记录内存分配的剖析数据,帮助分析内存使用的热点和分配情况。
  • main-1-cpu-1227152939.pprof:记录 CPU 使用的剖析数据,帮助分析 CPU 时间的消耗情况。
  • main-1-block-1227152939.pprof:记录阻塞操作的剖析数据,帮助分析阻塞操作的频率和开销。

内存OOM,那最重要的当然是mem文件,也就是内存分配剖析数据,不过很不幸,服务重启速度太快了,运维大佬dump的时候正好处于服务刚重启的时候,所以mem文件中显示的内存才占用不到20M,并且占比上也没看出有什么问题。想让运维再帮忙dump一下内存快要OOM的时候,但是为了线上服务的稳定性版本已经回退了,无法重新dump,只能从其他几个文件中查找问题了。

除了内存占用分析,在性能问题分析中CPU占用分析也是极为重要的一环,这一查看就有意思了,CPU总的使用率虽然不高,但是这个占比就比较奇怪了。第一占比的runtime.step是Go的运行时系统负责管理内存分配、垃圾回收、调度goroutine等底层操作,这个暂且不管,占比第二的居然是runtime.selectgo,这个就非常诡异了,select一般用于channel的非阻塞调用,但是问题是新增代码中没有地方显示地调用了select,那可以初步判断是底层源码中某处一直在调用select函数,不过目前还不知道是谁触发的这个调用,还需要继续查看其他文件。

之后继续查看互斥锁的情况,其实这个文件在目前这种情况下排查的价值已经不大了,因为出现问题的是内存溢出而不是CPU占用率,并且CPU占用率确实不是很高,而且Go中是有检索死锁的机制,大部分死锁是能够被Go发现并报一个deadlock错误,打开文件之后发现果然没有死锁发生。

接下来查看阻塞操作的分析情况,从解析结果中可以看出,select的阻塞时间遥遥领先,select出现这种情况只会是存在case但是没有default的时候,当所有case不符合的时候,负责这个select的goroutine会阻塞住直到存在符合的case出现才会唤醒继续走下去,当时我看到这我满脑子问号,谁家好人select不加default啊?

再查看线程创建情况,由于pod刚启动不久,所以这个文件也看不出什么东西,很正常的线程创建。

看到这里还是没能定位到问题所在,但是别急,我们还有最重要的文件还没看,那就是trace文件,它可以记录程序执行的详细跟踪信息,包括函数调用、Goroutine 的创建和调度,使用go自带的pprof分析工具打开trace文件

go tool trace main-1-trace-1227102939.pprof

会出现以下本地页面:

在Goroutine分析中,可以锁定真正的问题所在了,在go-zero的core包下的collection文件在不到一秒内创建了两万多的Goroutine,虽然两万多数量不多,但是这个速度十分异常,最重要的是这个定时轮就很奇怪,这个项目中根本没有定时任务,接下来就很容易查询了,只要查找这次提交的代码中哪里使用到了collection包。

经过一番全局搜索后,最终确定了问题代码:

func NewXXXLogic(svcCtx *svc.ServiceContext, ctx context.Context) *XXXLogic { cache, _ := collection.NewCache(30 * time.Second) return &XXXLogic{ Logger: logx.WithContext(ctx), svcCtx: svcCtx, ctx: ctx, localCache: cache, } }

在新上线的版本中只有这一处用到了collection包,原本这里的意思是将建立一个缓存放到上下文中去传递,但是乍一看我没有看出有什么问题,过期时间也设置了,按照我原有理解过期时间到了就会自动释放掉,为什么还是会内存溢出了?但是我忽然意识到应该不是缓存引发的内存溢出,可能是协程过多引发的内存溢出,因为一个初始协程是2KB左右,如果数量过多也会造成内存不够。

为了探究根本原因,我点进了collection包的源码进行查看,在其中NewCache()方法中找到了造成协程数异常增加的定时轮创建方法NewTimingWheel()。

之后点进去这个方法进一步查看,可以看到这个定时轮的结构体,里面包含了四个channel以及一些其他数据结构,粗略估计这一个TimingWheel结构体所占内存要达到一百字节以上,这是一个比较庞大的对象,如果无限制的创建下去很容易造成内存OOM发生。

相关新闻

  • WittyHub与PostgreSQL全文搜索:高性能AI技能检索技术详解
  • Kiran Biometrics API详解:指纹采集、验证与模板管理的完整接口指南 [特殊字符]
  • WittyHub核心功能深度解析:智能搜索、安全检测与多版本管理

最新新闻

  • WordPress渗透测试实战:从信息收集到权限提升的完整攻防演练
  • 如何安全使用大气层系统:Switch破解的终极完整指南
  • Spotify-GitHub集成安全实践:API密钥管理与OAuth防护指南
  • 企业级JMeter部署实战:从单机到分布式集群的完整指南
  • Playwright MCP:用自然语言驱动浏览器自动化的AI智能体实践
  • 从攻防视角构建Web应用安全自检体系:JS安全、接口防护与供应链漏洞治理

日新闻

  • Python Playwright录制功能:从零到一构建自动化测试脚本
  • 如何用开源工具永久保存你心爱的小说:novel-downloader全攻略
  • In-Context Learning不是教知识,而是模式对齐:从5个示例到100个工业级样本的真相

周新闻

  • Windows字体自定义终极方案:No!! MeiryoUI完全指南
  • Deepin Boot Maker:告别命令行,3分钟制作Linux启动盘的智能解决方案
  • Plain Craft Launcher 2:重新定义你的Minecraft游戏体验

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号