我正在使用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上对我的应用程序进行了负载测试,具有以下配置
网络性能非常出色。我在执行代码时查看了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运行时环境(版本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,混合模式)
答案 0 :(得分:2)
使用工作线程来查看是否可以提高性能。 NioEventLoopGroup()
的标准构造函数创建了默认的事件循环线程数:
DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
"io.netty.eventLoopThreads", Runtime.getRuntime().availableProcessors() * 2));
正如您所看到的,您可以将io.netty.eventLoopThreads
作为启动参数传递,但我通常不会这样做。
您还可以在NioEventLoopGroup()
的构造函数中传递线程数。
在我们的环境中,我们有netty服务器接受来自数百个客户端的通信。通常一个boss线程来处理连接就足够了。工作线程数量需要缩放。我们用这个:
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;
}
}
所以在我们的例子中我们只使用一个boss线程。工作线程取决于是否已发出启动参数。如果没有,那么使用核心* 2,但不要超过12。
您必须测试自己,尽管哪些数字最适合您的环境。
答案 1 :(得分:0)
这是从实施非常简单的HTTP→Kafka叉车得到的发现:
EpollEventLoopGroup
。
简单的自动替换NioEventLoopGroup
→EpollEventLoopGroup
使我的性能提高了30%。LoggingHandler
(如果有)会导致CPU使用率下降(在我的情况下,CPU下降几乎是令人难以置信的:80%)。