在Linux机器上对Netty 4.1进行性能调整

Sac*_*tra 7 java linux epoll nio netty

我正在使用Netty 4.1 Beta3构建一个消息传递应用程序来设计我的服务器,并且服务器理解MQTT协议.

这是我的MqttServer.java类,它设置Netty服务器并将其绑定到特定端口.

        EventLoopGroup bossPool=new NioEventLoopGroup();
        EventLoopGroup workerPool=new NioEventLoopGroup();

        try {

            ServerBootstrap boot=new ServerBootstrap();

            boot.group(bossPool,workerPool);
            boot.channel(NioServerSocketChannel.class);
            boot.childHandler(new MqttProxyChannel());

            boot.bind(port).sync().channel().closeFuture().sync();

        } catch (Exception e) {
            e.printStackTrace();
        }finally {          
            workerPool.shutdownGracefully();
            bossPool.shutdownGracefully();
        }
    }
Run Code Online (Sandbox Code Playgroud)

现在,我在Mac上对我的应用程序进行了负载测试,具有以下配置 在此输入图像描述

网络性能非常出色.我在执行代码时查看了jstack,发现netty NIO产生了大约19个线程,但似乎没有一个线程等待通道或其他东西.

然后我在linux机器上执行了我的代码

在此输入图像描述

这是一款2核15GB机器.问题是我的MQTT客户端发送的数据包似乎需要花费很长时间才能通过netty管道,并且在获取jstack时我发现有5个netty线程,所有这些都被困在这个

    ."nioEventLoopGroup-3-4" #112 prio=10 os_prio=0 tid=0x00007fb774008800 nid=0x2a0e runnable [0x00007fb768fec000]
        java.lang.Thread.State: RUNNABLE
             at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
             at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)
             at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:79)
             at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
             - locked <0x00000006d0fdc898> (a 
io.netty.channel.nio.SelectedSelectionKeySet)
             - locked <0x00000006d100ae90> (a java.util.Collections$UnmodifiableSet)
             - locked <0x00000006d0fdc7f0> (a sun.nio.ch.EPollSelectorImpl)
             at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
             at io.netty.channel.nio.NioEventLoop.select(NioEventLoop.java:621)
             at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:309)
             at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:834)
             at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
             at java.lang.Thread.run(Thread.java:745)
Run Code Online (Sandbox Code Playgroud)

这是一些与linux机器上的epoll相关的性能问题.如果是,则应对netty配置进行哪些更改以处理此问题或提高性能.

编辑

本地系统上的Java版本是: -

java版"1.8.0_40"Java(TM)SE运行时环境(版本1.8.0_40-b27)Java HotSpot(TM)64位服务器VM(版本25.40-b25,混合模式)

AWS上的Java版本是: -

openjdk版本"1.8.0_40-internal"OpenJDK运行时环境(build 1.8.0_40-internal-b09)OpenJDK 64位服务器VM(内置25.40-b13,混合模式)

Moh*_*-Aw 2

尝试一下工作线程,看看这是否可以提高性能。标准构造函数NioEventLoopGroup()创建默认数量的事件循环线程:

DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
            "io.netty.eventLoopThreads", Runtime.getRuntime().availableProcessors() * 2));
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,你可以io.netty.eventLoopThreads作为启动参数传递,但我通常不这样做。

您还可以在 的构造函数中传递线程数量NioEventLoopGroup()

在我们的环境中,我们拥有接受来自数百个客户端的通信的网络服务器。通常,一个主线程来处理连接就足够了。不过,工作线程数量需要缩放。我们用这个:

private final static int BOSS_THREADS = 1;
private final static int MAX_WORKER_THREADS = 12;
Run Code Online (Sandbox Code Playgroud)
EventLoopGroup bossGroup = new NioEventLoopGroup(BOSS_THREADS);
EventLoopGroup workerGroup = new NioEventLoopGroup(calculateThreadCount());
Run Code Online (Sandbox Code Playgroud)
private int calculateThreadCount() {
    int threadCount;
    if ((threadCount = SystemPropertyUtil.getInt("io.netty.eventLoopThreads", 0)) > 0) {
        return threadCount;
    } else {
        threadCount = Runtime.getRuntime().availableProcessors() * 2;
        return threadCount > MAX_WORKER_THREADS ? MAX_WORKER_THREADS : threadCount;
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,在我们的例子中,我们只使用一个 boss 线程。工作线程取决于是否给出了启动参数。如果不是,则使用核心 * 2,但不得超过 12 个。

您必须自行测试哪些数字最适合您的环境。

  • 双核上的 10k 线程可能会适得其反,并且还可能导致速度缓慢。http://stackoverflow.com/questions/481970/how-many-threads-is-too-many (3认同)