Netty 线程模型在客户端连接多的情况下如何工作?

Posted

技术标签:

【中文标题】Netty 线程模型在客户端连接多的情况下如何工作?【英文标题】:How does the Netty threading model work in the case of many client connections? 【发布时间】:2011-12-15 07:23:44 【问题描述】:

我打算在即将到来的项目中使用 Netty。该项目将充当客户端和服务器。特别是它会建立和维护与各种服务器的许多连接,同时为自己的客户端提供服务。

现在,NioserverSocketChannelFactory 的文档很好地指定了服务器端的线程模型 - 每个绑定的监听端口在整个过程中都需要一个专用的 boss 线程,而连接的客户端则需要在 worker 线程上以非阻塞方式处理。具体来说,一个工作线程将能够处理多个连接的客户端。

但是,NioClientSocketChannelFactory 的文档不太具体。这似乎也利用了 bossworker 线程。但是,文档指出:

一个 NioClientSocketChannelFactory 有一个老板线程。它根据请求进行连接尝试。一旦连接尝试成功,boss 线程将连接的 Channel 传递给 NioClientSocketChannelFactory 管理的工作线程之一。

工作线程似乎也以与服务器案例相同的方式运行。

我的问题是,这是否意味着从我的程序到外部服务器的每个连接都会有一个专用的 boss 线程?如果我建立数百或数千个这样的连接,这将如何扩展?

作为旁注。将单个 Executor(缓存线程池)同时用作 ChannelFactory 的 bossExecutorworkerExecutor 是否有任何不利的副作用?在不同的客户端和/或服务器 ChannelFactory 实例之间重用呢? This is somewhat discussed here,但我发现这些答案不够具体。谁能详细说明一下?

【问题讨论】:

由于 NioClientSocketChannelFactory 和 OioClientSocketChannelFactory 可以很容易地相互替换,您现在可以选择其中任何一个。在您准备好进行一些性能测试后,您可以切换到另一个,看看它是否会提供更好或更差的性能。对于非常简单的情况,我在这里完成了此操作:gist.github.com/1120694 注意:它们是可替换的,但在不正确使用的情况下会有所不同 - 我在上面提到的要点中对此有评论。 @IvanSopov 我从来没有真正考虑过使用 ChannelFactories 的 Oio 版本,因为我知道它们每个连接都使用一个专用线程,我对线程数感到不舒服与连接数成正比。我担心 NioClientSocketChannelFactory 也会这样做(针对客户端,而不是针对服务器),但现在已经被证明是错误的。 【参考方案1】:

这不是您关于 Netty 客户端线程模型如何工作的问题的真正答案。但是您可以使用相同的 NioClientSocketChannelFactory 创建单个 ClientBootstrap 和多个 ChannelPipelineFactorys ,然后建立大量连接。请看下面的示例。

public static void main(String[] args)

    String host = "localhost";
    int port = 8090;
    ChannelFactory factory = new NioClientSocketChannelFactory(Executors
            .newCachedThreadPool(), Executors.newCachedThreadPool());
    MyHandler handler1 = new MyHandler();
    PipelineFactory factory1 = new PipelineFactory(handler1);
    AnotherHandler handler2 = new AnotherHandler();
    PipelineFactory factory2 = new PipelineFactory(handler2);
    ClientBootstrap bootstrap = new ClientBootstrap(factory);
    // At client side option is tcpNoDelay and at server child.tcpNoDelay
    bootstrap.setOption("tcpNoDelay", true);
    bootstrap.setOption("keepAlive", true);
    for (int i = 1; i<=50;i++)
        if(i%2==0)
            bootstrap.setPipelineFactory(factory1);
        else
            bootstrap.setPipelineFactory(factory2);
        

        ChannelFuture future = bootstrap.connect(new InetSocketAddress(host,
                port));

        future.addListener(new ChannelFutureListener()
        
            @Override
            public void operationComplete(ChannelFuture future) throws Exception
            
                future.getChannel().write("SUCCESS");
            
        );
    

它还展示了如何为不同的连接设置不同的管道工厂,因此,根据您建立的连接,您可以调整通道管道中的编码器/解码器。

【讨论】:

是的,这很好。我知道您已经可以为服务器版本执行此操作,但我没有考虑为客户端版本执行此操作。但是,它不会仍然为我从它创建的每个基于 ClientBootstrap 的连接消耗一个来自 bossExecutor 的专用线程,就像它对我在服务器端绑定的 ServerBootstrap 实例所做的那样?还是我误解了 NioClientSocketChannelFactory 的工作原理? 您实际上也可以执行此客户端引导实例。查看更新的代码。 感谢您为我确认。我仍然非常有兴趣更多地了解老板线程在客户端连接案例中的作用,但至少现在我对存在一对一关系的担忧已经消除。 netty 社区 nabble 很活跃,你可以在那里问。 Trustin 通常会自己回答这些问题。 jboss.org/netty/community【参考方案2】:

我不确定您的问题是否已得到解答。这是我的答案:有一个 Boss 线程同时管理应用程序中所有待处理的 CONNECT。它使用 nio 处理单个(Boss)线程中的所有当前连接,然后将每个成功连接的通道交给其中一个工作人员。

【讨论】:

【参考方案3】:

您的问题主要与性能有关。单线程在客户端上的扩展性非常好。

哦,nabble 已经关闭了。您仍然可以在那里浏览存档。

【讨论】:

以上是关于Netty 线程模型在客户端连接多的情况下如何工作?的主要内容,如果未能解决你的问题,请参考以下文章

Netty线程模型

netty线程模型运用到自己的项目之中

Netty模型篇一:Netty 线程模型架构 & 工作原理 解读

netty学习01-IO模型

正确理解线程池

详解BIOAIONIO Netty 知识点和工作原理