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

Posted

技术标签:

【中文标题】为啥我们真的需要多个 netty boss 线程?【英文标题】:Why do we really need multiple netty boss threads?为什么我们真的需要多个 netty boss 线程? 【发布时间】:2016-03-20 09:53:32 【问题描述】:

我真的很困惑老板组的线程数。我想不出我们需要多个老板线程的情况。在do we need more than a single thread for boss group? 中,Netty 的创建者说,如果我们在不同的服务器引导程序之间共享 NioEventLoopGroup,则多个老板线程很有用,但我不明白其中的原因。

考虑这个简单的 Echo 服务器:

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 个线程的 bossGroup 和一个带有 4 个线程的 workerGroup,并将两个事件组共享给绑定到两个不同端口(例如 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)?

谢谢,

【问题讨论】:

如果答案有帮助,请将其标记为已接受。 【参考方案1】:

Netty 的创建者说,如果我们共享,多个老板线程很有用 不同服务器引导程序之间的 NioEventLoopGroup,但我没有看到 原因。

正如 Norman Maurer 所说,没有必要,但它非常有用。

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

同样适用于工人 EventLoopGroup

【讨论】:

那么一个boss线程可以处理多个连接,但不能同时处理?而且,拥有多个老板线程很有用(例如,在我们期望多个同时连接的网络服务器中?)另外,我的理解或工作线程是否正确?谢谢。 @BestCoderEver 老板线程处理连接并将处理传递给工作线程。是的,拥有多个boss线程很有用。但不需要太多,因为一般工作线程的工作时间比老板线程的时间长。【参考方案2】:

当你 bind() 一个新端口时,Netty 将一个新的 ServerSocketChannel 注册到 bossGroup 中的 next() 事件循环,所以我认为多线程 boos 可以用于多个端口应用程序。

【讨论】:

以上是关于为啥我们真的需要多个 netty boss 线程?的主要内容,如果未能解决你的问题,请参考以下文章

8. Netty中线程处理 - NioEventLoopGroup,NioEventLoop

OpenTSDB原理系列-线程模型

Dubbo剖析-线程模型

万分之一错误率问题的分析及定位

Netty 专栏深入浅出 Netty read

本人对于netty框架的一些理解,怎么与网站上的websock建立连接