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

29

我打算在即将开始的项目中使用Netty。该项目将作为客户端和服务器同时存在。尤其重要的是,它将在同时服务自身客户端的同时与多个服务器建立和维护许多连接。

现在,NioServerSocketChannelFactory 的文档相当明确地规定了服务器端的线程模型 - 每个绑定侦听端口都需要一个专用的boss线程,而连接的客户端将在worker线程上以非阻塞方式处理。具体来说,一个工作线程将能够处理多个已连接的客户端。

然而,NioClientSocketChannelFactory 的文档则不是很具体。它似乎也同时利用了bossworker线程。但是文档说明:

一个NioClientSocketChannelFactory有一个boss线程。它会在请求时进行连接尝试。一旦连接尝试成功,boss线程将把连接的通道传递给NioClientSocketChannelFactory管理的其中一个worker线程。

工作线程似乎也与服务器端的情况相同。

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

顺便说一下,如果将单个Executor(缓存线程池)同时用作bossExecutorworkerExecutor以及ChannelFactory,是否会有任何负面影响?在不同的客户端和/或服务器ChannelFactory实例之间也是如此吗? 这里有些讨论,但我觉得那些答案不够具体。有人可以详细说明吗?


由于NioClientSocketChannelFactory和OioClientSocketChannelFactory可以轻松地相互替换,因此您现在可以选择任何一个。当您准备进行一些性能测试时,您可以切换到另一个并查看它是否会提供更好或更差的性能。对于非常简单的情况,我在这里已经做到了:https://gist.github.com/1120694注意:它们是可替换的,但在不正确使用的情况下行为略有不同-我在上面提到的要点中有评论。 - Ivan Sopov
1
@IvanSopov 我从未真正考虑过使用_ChannelFactories_的_Oio_版本,因为我知道它们会为每个连接使用一个专用线程,而我不希望线程计数与连接计数成正比。我的担忧是_NioClientSocketChannelFactory_也会这样做(对于客户端,而不是服务器),但现在这一点已经被证明是错误的。 - Jiddo
3个回答

14

这并不是回答您有关Netty客户端线程模型如何工作的真正答案。但是您可以使用相同的NioClientSocketChannelFactory创建单个ClientBootstrap,其中包含多个ChannelPipelineFactory,从而建立大量连接。请参考下面的示例。

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的工作原理? - Jiddo
你实际上也可以只做一次客户端引导。请查看更新后的代码。 - Abe
谢谢您确认这一点。我仍然非常有兴趣了解一下在客户端连接情况下老板线程的作用,但至少现在我对于存在一对一关系的担忧已经被排除了。 - Jiddo
Netty社区的Nabble非常活跃,你可以在那里提问。Trustin通常会亲自回答这些问题。http://www.jboss.org/netty/community - Abe

1

我不确定你的问题是否已经得到解答。这是我的回答:有一个单独的Boss线程在同时管理应用程序中所有未完成的连接。它使用nio来处理单个(Boss)线程中的所有当前连接,然后将每个成功连接的通道移交给其中一个工作线程。


0

你的问题主要涉及性能。单线程在客户端上的扩展非常好。

哦,而且Nabble已经关闭了。您仍然可以浏览那里的存档。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接