今天一个核心系统宕机了,导致所有服务不可用,在自动重启后又恢复了。
下面记录整个排查过程
我们使用的环境是 docker
JDK 版本 1.8
参数是
1 2 3
| JVM_OPTIONS="-Xms2048M -Xmx2048M -Xss512K -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=68 -XX:ParallelGCThreads=4 -XX:+CMSClassUnloadingEnabled -Xloggc:logs/gc.log -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+PrintGCDetails" LIMIT_MEMORY=2.5G SERVICE_REPLICAS=4
|
新生代老年代默认比例是 1:2
最大内存是 2G
老年代是 1365M
通过 JProfiler 分析 dump 文件
发现有一个大对象,600 多 M
查看对象引用
发现对象是来自于 MemoryCacheStore 这个类,然后可以定位到代码。
代码发现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| private static final SecurityMemoryCacheManager cacheManager = new SecurityMemoryCacheManager();
------- private static class SecurityMemoryCacheManager extends SimpleCacheManager {
@Override protected Cache getMissingCache(String name) { return new ConcurrentMapCache(CACHE_NAME_PREFIX + name); } }
------- public ConcurrentMapCache(String name) { this(name, new ConcurrentHashMap<>(256), true); }
|
代码确实发现了一个 ConcurrentHashMap
进一步分析业务逻辑,
发现这个 map 是第一个架构师写的用于存储 token 和权限的。
实际上已经没有用到了,但是陈年老代码,也没有删除。
为什么会在这个时间出现也分析了一下原因。
以前这个系统经常有功能要上线,一般一个星期就会发版重启一次,但是年前那段时间,没有新功能,也就没有发版,又过了一个年,导致内存占用越来越多。
直到 OOM。索性系统会自动恢复,没有造成巨大影响。