1. 问题现象
一天运维同学找过来,现网有台机器频繁fullgc,几乎1分钟一次。
2. 问题定位分析
这种问题比较好定位分析,因为应用进程还在提供服务。先保留现场,取heap dump回来分析。
相关命令参考之前帖子Troubleshooting系列-JAVA虚拟机命令总结
给出命令
//123 通过jps获取应用进程替换
jmap -dump:format=b,file=123.bin 123
jstack -1 123>123jstack.txt
jmap dump:live,format=b,file=123.bin2 123
取回heap dump后,使用mat工具分析,mat工具使用参考Troubleshooting系列-MAT使用介绍以实战
简单分析后,发现dubbo的org apache,dubbo,remoting.transportnetty4.NettyChannel
疑似存在内存泄露问题
发现问题后,寻找应用对应的版本,发现版本还是老版本dubbo 3.1.1
,其他应用dubbo版本都已经升级到dubbo 3.2.0
。怀疑是dubbo版本不兼容或者dubbo老版本有问题导致的。
现阶段解决方式比较简单,该应用已经好久没重启了,先重启,减少堆中NettyChannel占用
应急处理大法,重启
3. 源码分析
翻看dubbo 3.1.1源码
先看NettyChannel
源码,主要就是存在CHANNEL_MAP
final class NettyChannel extends AbstractChannel {
private static final Logger logger = LoggerFactory.getLogger(NettyChannel.class);
private static final ConcurrentMap<org.jboss.netty.channel.Channel, NettyChannel> CHANNEL_MAP = new ConcurrentHashMap<org.jboss.netty.channel.Channel, NettyChannel>();
private final org.jboss.netty.channel.Channel channel;
private final Map<String, Object> attributes = new ConcurrentHashMap<String, Object>();
private NettyChannel(org.jboss.netty.channel.Channel channel, URL url, ChannelHandler handler) {
...
}
static NettyChannel getOrAddChannel(org.jboss.netty.channel.Channel ch, URL url, ChannelHandler handler) {
if (ch == null) {
return null;
}
NettyChannel ret = CHANNEL_MAP.get(ch);
if (ret == null) {
NettyChannel nc = new NettyChannel(ch, url, handler);
if (ch.isConnected()) {
ret = CHANNEL_MAP.putIfAbsent(ch, nc);
}
if (ret == null) {
ret = nc;
}
}
return ret;
}
static void removeChannelIfDisconnected(org.jboss.netty.channel.Channel ch) {
if (ch != null && !ch.isConnected()) {
CHANNEL_MAP.remove(ch);
}
}
...
可能是调用getOrAddChannel
的地方,没有在channel关闭的时候调用removeChannelIfDisconnected或者close方法,查看其调用方法
发现这个类NettyPortUnificationServerHandler
比较可疑,channelInactive
或者exceptionCaught
没有处理
这个版本不是最终版本,同时出现好久了,一般在github已经有其他人会遇到,在github.com/apache/dubb… 上搜索NettyChannel,果然发现类似的问题
已经有了修复merge,如下 github.com/apache/dubb…
主要改动就是加了一个装饰类,重写了channelInactive
,把nettychannel移除
4.总结
后台应用中间件升级版本需要保持一致,对于无需求的应用也要及时升级版本,避免出现已知问题。