今天早上小伙伴反馈某个服务调用超时率比较明显,对应的服务发现出现 ClientAbortException,检查监控惊讶发现有好几个 POD 的内存使用率已经顶天了:
查看其中的一个 POD GC:
从上面的图来看内存泄漏无疑了,这个时候 heap dump + MAT 就出场了。
2000 years later······
在经历了漫长的 dump & transport,打开 hprof 文件,问题一眼就映入眼中:
TsrReplayUtil中chainIdMap( ConcurrentHashMap ) 消耗了 90+%的内存!!!!!接着进一步展开:
可以得到:1. map ( 集合 ) 没有设置上限;2. value ( 集合中的集合 ) 没有设置上限。
那我们能有什么做的?
- 限制资源使用上限,特别是容易忽略的集合中集合,这在诸如中间件中非常常见 ( 如在某些 LB 中,正是因为 http header 超过设定大小返回 409 );
- 使用 SoftReference & WeakReference,哪怕疏忽忘记限制资源仍然不会有过多影响 ( 同样对于我们常用的 Google Guava Cache,可以通过
CacheBuilder.newBuilder().softValues()合理使用 )。