java 使用 Netty 和 NIO 的高并发 HTTP

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5453602/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 11:12:08  来源:igfitidea点击:

Highly concurrent HTTP with Netty and NIO

javahttpconcurrencyclojurenetty

提问by Toby Hede

I am working through the example Netty HTTP Client codein order to make http requests within a concurrent, threaded environment.

我正在研究示例 Netty HTTP 客户端代码,以便在并发线程环境中发出 http 请求。

However, my system breaks completely (with a slew of exceptions) at fairly low throughput.

然而,我的系统在相当低的吞吐量下完全崩溃(有很多例外)。

In almost pseudo-code:

在几乎伪代码中:

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);

In the example, to make a request I create a ClientBootstrap, and from there (through a few hoops) a Channel to write the HTTPRequest.

在示例中,为了发出请求,我创建了一个 ClientBootstrap,并从那里(通过几个箍)一个 Channel 来编写 HTTPRequest。

This all works and is good.

这一切都有效并且很好。

However, in a concurrent situation, should every request be going through the same hoops? I think that is what's breaking things for me at the moment. Should I be reusing the connection or structuring my client in an entirely different way?

但是,在并发情况下,每个请求都应该经过相同的循环吗?我认为这就是目前对我来说破坏事情的原因。我应该重用连接还是以完全不同的方式构建我的客户端?

Also: I am doing this in Clojure, if that makes any difference at all.

另外:我正在 Clojure 中这样做,如果这有什么不同的话。

采纳答案by Yanick Rochon

No, you're doing things right. You must, however, keep a reference to your Channelinstance. Once you have that channel, as long as it is open, you don't need to create another bootstrap. (If that's what you're doing.)

不,你做对了。但是,您必须保留对您的Channel实例的引用。一旦拥有该通道,只要它处于打开状态,就不需要创建另一个引导程序。(如果这就是你正在做的。)

This is what I used in a recent project :

这是我在最近的一个项目中使用的:

class ClientConnection(constructor)

类 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)

类 ClientConnection.connect(字符串主机,int 端口)

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();
    }
});

So, basically, I only keep a reference to bootstrapand channel, however the former is pretty much not used outside of these lines of code.

所以,基本上,我只保留对bootstrapand的引用channel,但是在这些代码行之外几乎不使用前者。

Note:you should only execute bootstrap.releaseExternalResources();once, when the application is exiting. In my case, the client sends some files then close the channel and exit.

注意:您应该只bootstrap.releaseExternalResources();在应用程序退出时执行一次。就我而言,客户端发送一些文件,然后关闭通道并退出。

Once you have a connected Channelinstance, you need only to use that one until you close it again. Once it is closed, you can recall the bootstrapto create a new Channelagain.

一旦你有一个连接的Channel实例,你只需要使用那个实例,直到你再次关闭它。关闭后,您可以再次调用bootstrap以创建新的Channel

Personally, I find Netty a little bit hard to understand at first, but once you grasp how it works, it is simply the best NIO framework in Java. IMO.

就我个人而言,我觉得 Netty 一开始有点难以理解,但是一旦你掌握了它的工作原理,它简直就是 Java 中最好的 NIO 框架。海事组织。