使用Netty和NIO实现高并发的HTTP请求

8
我正在研究Netty HTTP客户端示例代码,以便在并发、线程环境中进行HTTP请求。然而,我的系统在相当低的吞吐量下完全崩溃(伴随着一连串的异常)。简单来说:
ClientBootstrap bootstrap = new ClientBootstrap(new NioClientSocketChannelFactory()) 
bootstrap.setPipelineFactory(new HttpClientPipelineFactory());

ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
Channel channel = future.awaitUninterruptibly().getChannel();

HttpRequest request = new DefaultHttpRequest();
channel.write(request);

在这个例子中,为了发起请求,我创建了一个ClientBootstrap,并通过一些步骤创建了一个Channel来编写HTTPRequest。
这一切都很正常和好。但是,在并发情况下,每个请求都应该通过相同的步骤吗?我认为这就是目前出现问题的原因。我应该重复使用连接还是以完全不同的方式构建我的客户端?
另外:我正在Clojure中进行此操作,如果有任何区别,请告诉我。

也许你应该使用 https://github.com/ztellman/aleph 吗? - PheliX
你有使用 Aleph 的经验吗?我尝试过另一个异步的 Clojure HTTP 客户端,但它无法达到我需要维持的吞吐量水平。 - Toby Hede
2个回答

7
不,你做得很对。但是,你必须保留对你的Channel实例的引用。一旦你拥有了这个通道,只要它是打开状态,你就不需要再创建另一个引导程序。(如果这是你正在做的事情。)
这是我在最近的项目中使用的代码: class ClientConnection (构造函数)
// Configure the client.
bootstrap = new ClientBootstrap(
    new NioClientSocketChannelFactory(
        Executors.newCachedThreadPool(),
        Executors.newCachedThreadPool()
    )
);

// Set up the pipeline factory.
bootstrap.setPipelineFactory(
    new ChannelPipelineFactory() {
        public ChannelPipeline getPipeline() throws Exception {
            return Channels.pipeline(
                // put your handlers here
            );
        }
    }
);

class ClientConnection.connect(String host, int port)

该方法用于建立客户端与服务器之间的连接,需要传入服务器主机名和端口号作为参数。
if (isConnected()) {
    throw new IllegalStateException("already connected");
}

// Start the connection attempt.
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));

channel = future.awaitUninterruptibly().getChannel();

// Wait until the connection is closed or the connection attempt fails.
channel.getCloseFuture().addListener(new ChannelFutureListener() {
    @Override
    public void operationComplete(ChannelFuture future) throws Exception {
        new Thread(new Runnable() {
            public void run() {
                // Shut down thread pools to exit
                // (cannot be executed in the same thread pool!
                bootstrap.releaseExternalResources();

                LOG.log(Level.INFO, "Shutting down");
            }
        }).start();
    }
});

因此,基本上我只保留对bootstrapchannel的引用,然而前者在这些代码行之外几乎不被使用。
注意:应该仅在应用程序退出时执行bootstrap.releaseExternalResources();一次。在我的情况下,客户端发送一些文件,然后关闭通道并退出。
一旦您拥有一个连接的Channel实例,您只需要使用它,直到再次关闭它。一旦关闭,您可以调用bootstrap以再次创建新的Channel
个人而言,我觉得Netty一开始有点难理解,但是一旦掌握了它的工作原理,它就是Java中最好的NIO框架。在我看来。

3
如果您想建立另一个连接并利用现有机器设备(底层的Netty NIO工作线程),则bootstrap也会很有用。 - Piotr Findeisen

1
Netty是在JVM中编写高并发HTTP服务的最佳方法,但它非常复杂,直接进行Interop也很困难,特别是当使用Clojure时。看看Donkey,它提供与Vert.x的Interop,Vert.x使用Netty作为后端。这种分层抽象了许多微妙的低级细节,如果做错了,可能会导致不稳定的服务。Donkey相对较新,因此尚没有太多关于它的文档。查看这个blog,它展示了一个使用Donkey在Clojure中实现基本新闻源微服务的开源项目。它详细介绍了架构、设计、编码和负载下的性能。

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