问题描述
我正在处理 示例 Netty HTTP 客户端代码 以便在并发的线程环境中发出 http 请求.
I am working through the example Netty HTTP Client code in order to make http requests within a concurrent, threaded environment.
但是,我的系统在相当低的吞吐量下完全崩溃(有大量异常).
However, my system breaks completely (with a slew of exceptions) at fairly low throughput.
几乎是伪代码:
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.
In the example, to make a request I create a ClientBootstrap, and from there (through a few hoops) a Channel to write the 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?
另外:我正在 Clojure 中执行此操作,如果这有什么不同的话.
Also: I am doing this in Clojure, if that makes any difference at all.
推荐答案
不,您做对了.但是,您必须保留对 Channel
实例的引用.一旦拥有该通道,只要它处于打开状态,就不需要创建另一个引导程序.(如果这就是你正在做的事情.)
No, you're doing things right. You must, however, keep a reference to your Channel
instance. 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.)
这是我在最近的一个项目中使用的:
This is what I used in a recent project :
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();
}
});
所以,基本上,我只保留对 bootstrap
和 channel
的引用,但是在这些代码行之外几乎不使用前者.
So, basically, I only keep a reference to bootstrap
and channel
, however the former is pretty much not used outside of these lines of code.
注意:你应该只在应用程序退出时执行一次bootstrap.releaseExternalResources();
.就我而言,客户端发送一些文件,然后关闭频道并退出.
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.
一旦你有一个连接的 Channel
实例,你只需要使用那个,直到你再次关闭它.关闭后,您可以调用 bootstrap
以再次创建新的 Channel
.
Once you have a connected Channel
instance, you need only to use that one until you close it again. Once it is closed, you can recall the bootstrap
to create a new Channel
again.
就我个人而言,一开始我觉得 Netty 有点难以理解,但是一旦你掌握了它的工作原理,它简直就是 Java 中最好的 NIO 框架.海事组织.
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 和 NIO 的高并发 HTTP的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!