1. 问题现象

一天运维同学找过来,现网有台机器频繁fullgc,几乎1分钟一次。

Troubleshooting系列-DUBBO中间版本导致应用频繁Fullgc的问题定位分析

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疑似存在内存泄露问题

Troubleshooting系列-DUBBO中间版本导致应用频繁Fullgc的问题定位分析

Troubleshooting系列-DUBBO中间版本导致应用频繁Fullgc的问题定位分析

发现问题后,寻找应用对应的版本,发现版本还是老版本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方法,查看其调用方法

Troubleshooting系列-DUBBO中间版本导致应用频繁Fullgc的问题定位分析
发现这个类NettyPortUnificationServerHandler比较可疑,channelInactive或者exceptionCaught没有处理

这个版本不是最终版本,同时出现好久了,一般在github已经有其他人会遇到,在github.com/apache/dubb… 上搜索NettyChannel,果然发现类似的问题

github.com/apache/dubb…

Troubleshooting系列-DUBBO中间版本导致应用频繁Fullgc的问题定位分析

Troubleshooting系列-DUBBO中间版本导致应用频繁Fullgc的问题定位分析

已经有了修复merge,如下 github.com/apache/dubb… 主要改动就是加了一个装饰类,重写了channelInactive,把nettychannel移除

Troubleshooting系列-DUBBO中间版本导致应用频繁Fullgc的问题定位分析

4.总结

后台应用中间件升级版本需要保持一致,对于无需求的应用也要及时升级版本,避免出现已知问题。