【问题标题】:Exception during Netty server shutdownNetty 服务器关闭期间的异常
【发布时间】:2014-07-17 23:54:21
【问题描述】:

我有在 Tomcat 上运行的应用程序。我使用 Netty 4 进行 websocket 处理。 Netty 服务器在 contextInitialized 方法中运行在 ServletContextListener 中,并在 contextDestroyed 中停止。

这是我的 Netty 服务器类:

public class WebSocketServer {

    private final int port;
    private final EventLoopGroup bossGroup;
    private final EventLoopGroup workerGroup;
    private Channel serverChannel;

    public WebSocketServer(int port) {
        this.port = port;
        bossGroup = new NioEventLoopGroup(1);
        workerGroup = new NioEventLoopGroup();
    }

    public void run() throws Exception {
        final ServerBootstrap b = new ServerBootstrap();
        b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
                .childHandler(new WebSocketServerInitializer());
        serverChannel = b.bind(port).sync().channel();
        System.out.println("Web socket server started at port " + port + '.');
        System.out
                .println("Open your browser and navigate to http://localhost:"
                        + port + '/');
    }

    public void stop() {
        if (serverChannel != null) {
            ChannelFuture chFuture = serverChannel.close();
            chFuture.addListener(new ChannelFutureListener() {

                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    shutdownWorkers();

                }
            });
        } else {
            shutdownWorkers();
        }
    }

    private void shutdownWorkers() {
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
    }
}

运行后一切正常,但是当我尝试停止 Tomcat 时出现异常:

INFO:非法访问:此 Web 应用程序实例已被停止。无法加载 io.netty.util.concurrent.DefaultPromise$3。最终的后续堆栈跟踪是由出于调试目的引发的错误以及试图终止导致非法访问的线程引起的,并且没有功能影响。 java.lang.IllegalStateException 在 org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1610) 在 org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1569) 在 io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:592) 在 io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:403) 在 io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:139) 在 java.lang.Thread.run(Thread.java:662)

Tomcat 挂断后。 可能是什么原因?

【问题讨论】:

  • shutdown-methods 通知线程停止,但可能不会等待所有线程完成。与此同时,Tomcat 继续关闭 webapp 和 webapp 中仍在运行的线程,出现错误,因为除其他外,Tomcat 卸载了 webapp 加载的所有类。
  • 谢谢,是有原因的。现在我使用 awaitTermination 来完成关机。并且Tomcat无一例外地停止正常。但它会在日志中写入下一条消息:Web 应用程序 [/MySite] 似乎已经启动了一个名为 [nioEventLoopGroup-3-2] 的线程,但未能停止它。这很可能造成内存泄漏。什么可能导致这种泄漏?
  • 这意味着一个线程没有停止运行并将webapp加载的类保存在内存中,因此内存使用量会随着webapp的每次重新部署而增加。但是你知道Tomcat支持websocketsnatively吗? IE。你不需要 Netty。
  • 我遇到了类似的问题并发布了解决方案。

标签: java tomcat netty


【解决方案1】:

我假设您在 Servlet.destroy() 的某个地方调用 shutdownWorkers() 或使用其他机制确保您的服务器在 servlet 停止/卸载时关闭。

那你需要做的

void shutdownWorkers() {
    Future fb = trbossGroup.shutdownGracefully();
    Future fw = workerGroup.shutdownGracefully();
    try {
        fb.await();
        fw.await();
    } catch (InterruptedException ignore) {}
}

这是因为shutdownGracefully() 返回了一个 Future,而且,你不用等待它的到来,就把试图关闭连接的东西留在压力很大的环境中。首先启动所有关闭,然后等到 futures 可用也是有意义的,这样它就可以并行运行并且发生得更快。

它为我解决了这个问题。显然,您可以在不使用swallowing InterruptedException 的情况下使其对您的系统更好,并将每个调用包装在一个不错的方法中,并为每个await() 设置合理的超时时间。总体来说很好的练习,但实际上你很可能不会在意代码中的这一点。

旁注:是的,对于 WebSockets,使用 Tomcat 的原生、符合标准且健壮的实现会更好。 Netty 在许多其他方面都很棒,但在这里可能是一个错误的工具。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-29
    • 2011-01-22
    • 1970-01-01
    • 2019-03-26
    • 1970-01-01
    • 1970-01-01
    • 2015-04-07
    相关资源
    最近更新 更多