为什么我们真的需要多个netty boss线程?

问题描述:

我真的很困惑老板组的线程数量。我无法弄清楚我们需要多个boss线程的场景。在do we need more than a single thread for boss group? Netty的创建者说,如果我们在不同的服务器引导程序之间共享NioEventLoopGroup,那么多个Boss线程是有用的,但我没有看到它的原因。为什么我们真的需要多个netty boss线程?

考虑这个简单的回声服务器:

public class EchoServer { 

private final int port; 
private List<ChannelFuture> channelFutures = new ArrayList<ChannelFuture>(2); 

public EchoServer(int port) { 
    this.port = port; 
} 

public void start() throws Exception { 

    EventLoopGroup bossGroup = new NioEventLoopGroup(1); 
    EventLoopGroup workerGroup = new NioEventLoopGroup(4); 

    for (int i = 0; i != 2; ++i) { 
     ServerBootstrap b = new ServerBootstrap(); 
     b.group(bossGroup, workerGroup) 
       .channel(NioServerSocketChannel.class) // the channel type 
       .childHandler(new ChannelInitializer<SocketChannel>() { 
        @Override 
        public void initChannel(SocketChannel ch) 
          throws Exception { 
         System.out.println("Connection accepted by server"); 
         ch.pipeline().addLast(
           new EchoServerHandler()); 
        } 
       }); 

     // wait till binding to port completes 
     ChannelFuture f = b.bind(port + i).sync(); 
     channelFutures.add(f); 
     System.out.println("Echo server started and listen on " + f.channel().localAddress()); 
    } 

    for (ChannelFuture f : channelFutures) 
     f.channel().closeFuture().sync(); 

    // close gracefully 
    workerGroup.shutdownGracefully().sync(); 
    bossGroup.shutdownGracefully().sync(); 
} 

public static void main(String[] args) throws Exception { 
    if (args.length != 1) { 
     System.err.println(
       "Usage: " + EchoServer.class.getSimpleName() + 
         " <port>"); 
     return; 
    } 
    int port = Integer.parseInt(args[0]); 
    new EchoServer(port).start(); 
} 

在上面的示例中,创建了1个线程和workerGroup与4个线程一个bossGroup和共享结合两个不同的端口都事件组以两种不同的自举(例如9000和9001)。下面是我的处理程序:

@ChannelHandler.Sharable 
public class EchoServerHandler extends ChannelInboundHandlerAdapter { 

@Override 
public void channelRead(ChannelHandlerContext ctx, 
         Object msg) throws Exception { 
    ByteBuf in = (ByteBuf) msg; 
    System.out.println("Server received: " + in.toString(CharsetUtil.UTF_8) + " from channel " + ctx.channel().hashCode()); 
    ctx.write(in); 
} 

@Override 
public void channelReadComplete(ChannelHandlerContext ctx) { 
    System.out.println("Read complete for channel " + ctx.channel().hashCode()); 
    // keep channel busy forever 
    while(true); 
} 

@Override 
public void exceptionCaught(ChannelHandlerContext ctx, 
          Throwable cause) { 
    cause.printStackTrace(); 
    ctx.close(); 
} 
} 

在我上面的处理程序中,我故意保持通道忙,做while(true);现在,如果我开始我的应用程序参数9000,它会创建结合在端口9000二服务器白手起家和9001

Echo server started and listen on /0:0:0:0:0:0:0:0:9090 
Echo server started and listen on /0:0:0:0:0:0:0:0:9091 

现在,如果我连接到两个端口,并开始发送数据,最大连接#这可接收为4,这是有道理的,因为我已经创造了4个工作线程和保持他们的信道忙而不将其关闭:

echo 'abc' > /dev/tcp/localhost/9000 
echo 'def' > /dev/tcp/localhost/9000 
echo 'ghi' > /dev/tcp/localhost/9001 
echo 'jkl' > /dev/tcp/localhost/9000 
echo 'mno' > /dev/tcp/localhost/9001 # will not get connected 

你也可以这样做:

telnet localhost 9000 -> then send data "abc" 
telnet localhost 9000 -> then send data "def" 
telnet localhost 9001 -> then send data "ghi" 
telnet localhost 9000 -> then send data "jkl" 
telnet localhost 9001 -> # will not get connected 

我做什么不明白的是,我有一个老板线程,我可以用两个服务器引导程序连接到两个端口。那么为什么我们需要多个boss线程(并且默认情况下,#boss线程是2 * num_logical_processors)?

感谢,

+0

如果答案有帮助,请将其标记为已接受。 – Suvitruf

了Netty的创造者说,如果我们不同的服务器之间白手起家共享 NioEventLoopGroup多线程的老板是有用的,但我没有看到 的原因吧。

正如Norman Maurer所说,这不是必要的,但它非常有用。

如果您为两个不同的引导程序使用1个线程,则意味着您无法同时处理与此引导程序的连接。所以在非常糟糕的情况下,当boss线程只处理一个引导程序的连接时,连接到另一个永远不会被处理。

相同的工人EventLoopGroup

+0

所以一个boss线程可以处理多个连接,但不能同时处理?而且,有多个boss线程是很有用的(例如,在一个Web服务器中,我们期望多个同时连接?)另外,我的理解或工作线程是否正确?谢谢。 – BestCoderEver

+0

@BestCoderEver老板线程处理连接并将处理传递给工作线程。是的,有多个boss线程是很有用的。但不需要太多,因为一般工作者线程比老板线程工作的时间更长。 – Suvitruf