使用 Netty 和 NIO 实现高并发 HTTP
我正在研究 示例 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 中执行此操作,如果这有任何区别的话。
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.
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.
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
不,你做的事情是对的。但是,您必须保留对
Channel
实例的引用。一旦您拥有该通道,只要它处于打开状态,您就不需要创建另一个引导程序。 (如果这就是你正在做的事情。)这是我在最近的项目中使用的:
class ClientConnection (构造函数)
class ClientConnection.connect(String host, int port)
所以,基本上,我只保留对
bootstrap
和channel
的引用,但是前者在这些代码行之外几乎不使用。注意:当应用程序退出时,您应该只执行一次
bootstrap.releaseExternalResources();
。就我而言,客户端发送一些文件,然后关闭通道并退出。一旦您拥有一个已连接的
Channel
实例,您只需使用该实例即可,直到您再次将其关闭为止。关闭后,您可以调用bootstrap
来再次创建新的Channel
。就我个人而言,我觉得 Netty 一开始有点难以理解,但是一旦你掌握了它的工作原理,它就是 Java 中最好的 NIO 框架。国际海事组织。
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 (constructor)
class ClientConnection.connect(String host, int port)
So, basically, I only keep a reference to
bootstrap
andchannel
, however the former is pretty much not used outside of these lines of code.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.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 thebootstrap
to create a newChannel
again.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 是在 JVM 中编写高并发 HTTP 服务的最佳方法,但它非常复杂且难以直接互操作,特别是在使用 Clojure 时。看一下 Donkey,它提供与 Vert.x 的互操作,Vert.x 使用 Netty 作为后端。这种分层抽象了许多细微的低级细节,如果处理不当,可能会导致服务不稳定。 Donkey 相对较新,因此还没有很多关于它的文档。查看这个博客,其中包含一个实现基本新闻提要的开源项目Clojure 中使用 Donkey 的微服务。它详细介绍了架构、设计、编码和负载下的性能。
Netty is the best approach to writing highly concurrent HTTP services in the JVM but it is very complicated and hard to interop with directly, especially if using Clojure. Take a look at Donkey which provides interop with Vert.x which uses Netty as the backend. This layering abstracts away a lot of the nuanced low level details that, if done wrong, can result in an unstable service. Donkey is relatively new so there isn't a lot of documentation about it yet. Check out this blog that features an open source project which implements a rudimentary news feed microservice in Clojure using Donkey. It goes into details on architecture, design, coding, and performance under load.