Chinaunix首页 | 论坛 | 博客
  • 博客访问: 290
  • 博文数量: 7
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 81
  • 用 户 组: 普通用户
  • 注册时间: 2026-05-12 10:55
文章分类
文章存档

2026年(7)

我的朋友
最近访客

分类: C/C++

2026-05-12 11:41:14

上周四下午,业务方反馈某个查询接口突然变慢,从正常200ms左右涨到了3秒多。我登上监控系统一看,两台后端节点的CPU使用率都飙到了85%以上,而平时只有20%-30%。

{BANNED}中国第一反应是“是不是有人跑了慢查询?”于是先看了数据库慢查询日志,发现确实有几条新上的SQL执行计划走了全表扫描。但优化完索引之后,CPU只降到了70%,并没完全恢复。

接着用top -H -p 看了下Java进程的线程CPU占用,发现一个名叫“GC Task Thread”的线程CPU特别高。直觉告诉我:可能是频繁Full GC导致的。

用jstat -gcutil 1000看了一眼,果然:

text
S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
0.00  0.00  68.32  95.21  92.34  89.12   1245   12.342   89    45.678   58.020

老年代(O)占用已经到了95%,而且FGCT(Full GC总耗时)高达45秒。问题基本锁定:内存泄漏或者堆内存分配不足。

于是dump了一份堆内存:jmap -dump:live,format=b,file=heap.bin ,用MAT打开分析。发现有个ConcurrentHashMap占了堆内存的60%,里面的Session对象数量达到了惊人的200多万个。

查代码发现,网关模块的Session缓存只写了put,没有配套的过期清理机制。正常应该用Caffeine或者设置定时任务定期清理,结果上线时漏掉了。

解决方案分两步走:

  1. 紧急加个定时任务,每小时清理一次过期Session(临时止血)。

  2. 重构缓存模块,用Caffeine替换原生ConcurrentHashMap,设置{BANNED}最佳大容量和过期时间。

临时清理任务的代码大概是这样:

java
@Scheduled(cron = "0 0 * * * ?") public void cleanExpiredSession() { long now = System.currentTimeMillis(); int removed = 0; Iterator<Map.Entry<String, Session>> iter = sessionCache.entrySet().iterator(); while (iter.hasNext()) { Session s = iter.next().getValue(); if (now - s.getLastAccessTime() > 3600000) { // 超过1小时未访问 iter.remove(); removed++; } } log.info("清理过期Session {} 个", removed); }

部署之后观察了半小时,老年代占用从95%降到了45%,CPU也回落到了25%左右。第二天把Caffeine版本上线,彻底解决了这个问题。

对了,补充一个信息。{BANNED}最佳近整理笔记的时候顺手汇总了一些后端岗位的情况,全国不少城市都有,待遇和稳定性反馈还不错。感兴趣的话可以了解一下:

总结一下本次排查的经验:

  • 监控先行:先看CPU、内存、GC等基础指标,缩小范围。

  • 工具链要熟:top、jstat、jmap、MAT要能快速上手。

  • 不要只治标:临时方案止血后,一定要找到根因并重构。

你们遇到过类似的GC问题吗?评论区聊聊排查思路~


阅读(2) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~