Netty能否作为客户端有效地处理大量传出连接



我正在创建一个客户端-服务器关系,通过该关系,单个客户端将使用持久TCP连接连接到任意数量的服务器。服务器的实际数量尚未确定,但设计目标是达到1000台。

我发现了一个使用直接Java NIO的例子,它几乎完全符合我的心理模型:

http://drdobbs.com/jvm/184406242

一般来说,它会打开所有通道,并将它们添加到监视java.nio.channels.Selector的单个线程中。特别是Selector的使用,使其能够比使用每个通道的标准线程更好地扩展。

我宁愿使用(稍微)更高级别的套接字框架,如Netty,而不是直接使用Java NIO。不幸的是,我还无法确定Netty将如何处理这样的案件。也就是说,我发现的例子和讨论都倾向于围绕服务器端,接受并发连接的分数。

但是,从客户的角度来做这件事呢?如果我创建了大量通道并等待它们的事件,Netty将如何在后端处理这一问题?

这不是对您问题的直接回答,但我希望它仍然有帮助。下面,我将为您描述一种确定您正在寻找的答案的方法。这是我最近为一个即将到来的项目自己做的事情。

与OIO(旧IO)相比,Netty框架和NIO的异步特性确实会为应用程序提供更好的内存和CPU使用特性。在Netty中处理缓冲区的方式也会有好处,因为它将帮助您避免复制字节缓冲区。重点是,所有的线程池和NIO细节都将为您处理,使您能够专注于业务逻辑。您提到了NIOSelector,您将从中受益;Netty的好处在于,您可以获得好处,而不必自己担心实现,因为它已经为您完成了。

我对客户端的理解是,它与服务器端非常相似,应该为您提供相应的性能提升(只要您的业务逻辑不会引入任何性能问题)。

我的建议是制作一个或多或少能满足你需求的原型。去掉任何耗时的细节,只需添加基本的Netty处理程序,您就可以制作出有效的东西。

然后,我将使用jmeter来调用您的客户端,以将负载应用到服务器和客户端。使用类似jconsole或jvisualvm的东西将向您展示客户端和服务器在负载下的性能特征。你也可以试试jprobe。您可以在jmeter中添加一个监听器来指示吞吐量。我建议在服务器模式下使用jmeter,客户端在另一台机器上,服务器在另一个机器上。这是一项前期工作,但如果你决定继续前进,你将准备好这些工具,以便在进行进一步测试时使用。

我怀疑一个不错的Netty实现,它不会引入任何无关的性能不佳的组件,会给你带来你想要的性能特征,但是,唯一可以确定的方法是在预期负载下测量系统。

您需要定义预期负载的样子以及在这种负载下所需的性能特征。有了这些输入,你就可以衡量你的系统,看看它是否能满足你的期望。我个人认为没有人能告诉你它是否会以期望的方式表现。你必须测量它。这是了解系统是否能满足你需求的唯一可靠方法。

我宁愿使用(稍微)更高级别的套接字框架,如Netty,而不是直接使用Java NIO

这是正确的做法。您可以尝试实现自己的NIO服务器和客户端,但既然您已经可以轻松获得高度精细化的框架,为什么还要这样做呢?

Netty将使用多达x个工作线程为您处理工作。每个工作线程都有一个Selector,用于向其注册Channels。使用的工作线程数量是可配置的,默认情况下为2*cpu计数。

如您在Netty文档的示例中所见[http://netty.io/docs/stable/guide/html/#start.9][1] 您可以精确地控制客户端上工作线程的数量(即底层选择器的数量)。Netty以简单的方式解决了许多很难处理的问题,例如NIO与SSL,并且有很多Zip的默认编码器/解码器。。。等我几周前开始使用Netty,它很快就出现了。(我建议下载包含所有示例代码的项目,其中有很多文档在上面的url上找不到。

            ChannelFactory factory = new NioClientSocketChannelFactory(
                      Executors.newCachedThreadPool(),
                      Executors.newCachedThreadPool());
            ClientBootstrap bootstrap = new ClientBootstrap(factory);
            bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
             public ChannelPipeline getPipeline() {
                    return Channels.pipeline(new TimeClientHandler());
             }
            });
            bootstrap.setOption("tcpNoDelay", true);
            bootstrap.setOption("keepAlive", true);
            bootstrap.connect(new InetSocketAddress(host, port));

祝你好运,

Renaud

最新更新