【问题标题】:Performance tuning for Netty 4.1 on linux machinelinux 机器上 Netty 4.1 的性能调优
【发布时间】:2015-08-02 17:51:48
【问题描述】:

我正在使用 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();
        }
    }

现在我在具有以下配置的 Mac 上对我的应用程序进行了负载测试

netty 的表现非常出色。我在执行代码时查看了 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)

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

编辑

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

java 版本“1.8.0_40” Java(TM) SE 运行时环境 (build 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 位服务器虚拟机(build 25.40-b13,混合模式)

【问题讨论】:

  • 您确定两台机器上的 java 版本相同吗?同样的JVM?
  • 试用最新版本 4.1.0.Beta5。我读到了一些关于 epoll 的修复。
  • @ArnaudPotier 。 JVM版本不同。
  • 你能在两台机器上运行“java -version”并更新你的答案吗?

标签: java linux netty nio epoll


【解决方案1】:

玩弄工作线程,看看这是否能提高性能。 NioEventLoopGroup() 的标准构造函数会创建默认数量的事件循环线程:

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

如您所见,您可以将 io.netty.eventLoopThreads 作为启动参数传递,但我通常不这样做。

也可以在NioEventLoopGroup()的构造函数中传递线程数。

在我们的环境中,我们有 netty 服务器,可以接受来自数百个客户端的通信。通常一个老板线程来处理连接就足够了。工作线程数量需要缩放。我们使用这个:

private final static int BOSS_THREADS = 1;
private final static int MAX_WORKER_THREADS = 12;

EventLoopGroup bossGroup = new NioEventLoopGroup(BOSS_THREADS);
EventLoopGroup workerGroup = new NioEventLoopGroup(calculateThreadCount());

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;
    }
}

所以在我们的例子中,我们只使用一个老板线程。工作线程取决于是否已给出启动参数。如果没有,则使用核心 * 2,但不要超过 12。

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

【讨论】:

  • 我之前已经尝试过,但无济于事。我们使用了大约 10k 个工作线程;)并且还指定了一个 CachedPoolExecutor 但这并没有以任何方式减少延迟。问题仍然存在。不过谢谢:)
  • 双核上的 10k 线程可能会适得其反,也可能导致速度变慢。 stackoverflow.com/questions/481970/how-many-threads-is-too-many
  • 我也尝试了 12 个线程。仍然没有给我所需的性能:(
【解决方案2】:

这是我实现一个非常简单的 HTTP → Kafka 叉车的发现:

  1. 考虑切换到EpollEventLoopGroup。 简单的自动替换 NioEventLoopGroupEpollEventLoopGroup 给了我 30% 的性能提升。
  2. 从管道中删除LoggingHandler(如果有的话)可以让您的 CPU 使用率下降(在我的情况下,CPU 下降几乎令人难以置信:80%)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-24
    • 1970-01-01
    • 1970-01-01
    • 2012-11-02
    • 2013-07-13
    • 1970-01-01
    • 2015-06-07
    相关资源
    最近更新 更多