我使用Netty 4创建了一个相当直接的服务器。我已经能够扩展它以处理几千个连接,并且它永远不会超过~40个线程。
为了测试它,我还创建了一个创建数千个连接的测试客户端。不幸的是,这会创建与连接一样多的线程。我希望尽量减少客户的线程。我已经看了很多帖子。许多示例显示单连接设置。 This和this表示要跨客户共享NioEventLoopGroup,我这样做。我获得了有限数量的nioEventLoopGroup,但在其他地方获得了每个连接的线程。我并没有故意在管道中创建线程,也不知道可能是什么。
以下是我的客户端代码设置的片段。它似乎应该根据我迄今为止所研究的内容保持固定的线程数。我是否应该做些什么来防止每个客户端连接的线程?
主要
final EventLoopGroup group = new NioEventLoopGroup();
for (int i=0; i<100; i++)){
MockClient client = new MockClient(i, group);
client.connect();
}
MockClient
public class MockClient implements Runnable {
private final EventLoopGroup group;
private int identity;
public MockClient(int identity, final EventLoopGroup group) {
this.identity = identity;
this.group = group;
}
@Override
public void run() {
try {
connect();
} catch (Exception e) {}
}
public void connect() throws Exception{
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new MockClientInitializer(identity, this));
final Runnable that = this;
// Start the connection attempt
b.connect(config.getHost(), config.getPort()).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
Channel ch = future.sync().channel();
} else {
//if the server is down, try again in a few seconds
future.channel().eventLoop().schedule(that, 15, TimeUnit.SECONDS);
}
}
});
}
}
答案 0 :(得分:1)
正如我之前多次发生的那样,详细解释问题让我更多地思考它,并且我遇到了这个问题。我想在这里提供它,如果其他人遇到同样的问题,创建成千上万的Netty客户端。
我的管道中有一条路径会创建一个超时任务来模拟客户端连接重启。事实证明,正是这个计时器任务正在为每个连接创建额外的线程,只要它接收到重启&#39;来自服务器的信号(经常发生)直到每个连接都有一个线程。
<强>处理程序强>
private final HashedWheelTimer timer;
@Override
protected void channelRead0(ChannelHandlerContext ctx, Packet msg) throws Exception {
Packet packet = reboot();
ChannelFutureListener closeHandler = new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
RebootTimeoutTask timeoutTask = new RebootTimeoutTask(identity, client);
timer.newTimeout(timeoutTask, SECONDS_FOR_REBOOT, TimeUnit.SECONDS);
}
};
ctx.writeAndFlush(packet).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
future.channel().close().addListener(closeHandler);
} else {
future.channel().close();
}
}
});
}
超时任务
public class RebootTimeoutTask implements TimerTask {
public RebootTimeoutTask(...) {...}
@Override
public void run(Timeout timeout) throws Exception {
client.connect(identity);
}
}