注意:我的I/O能力不强,因此在进一步的推理中我可能是错的。
首先,我想了解一下tomcat连接器是如何工作的。
Tomcat 9具有3个连接器: NIO , APR 和 NIO2 。
在写这篇文章之前,我读了这篇
Choosing tomcat connectors,看起来Apache Tomcat Connector Selection
简而言之,我理解这一点:
返回准备进行I/O操作的 channel 的标识符。
应用程序的任务是绕过循环中的所有标识符
并执行相应的操作。
完成处理程序-接口(interface)的实现
java.nio.channels.CompletionHandler。方法启动请求的
在单独的线程上进行操作,然后将控制权传递给下一个线程。什么时候
请求的操作已完全执行,触发了
开始操作,完成操作所给出的方法
处理程序。异步和 NIO 之间的主要区别是
AIO 在多线程环境中工作:操作不是
在启动它们的流中进行表演。手术
NIO 通过多路 channel 在单个线程中执行。
我有以下问题:
1)如果我不在tomcat上使用TSL,在 NIO 之前, ARP 有什么优势?我在预热后测试了我的应用程序,并且发现 ARP 处理请求的速度比 NIO 慢,并且偶尔会暂停请求。 JIT> native 代码?或者在某些条件下它可以运行得更快?
2)如果 NIO2 使用hadnler回调,这是否意味着我需要分配更多线程?
3) NIO2 是否比 NIO 快?因为乍看之下, NIO 线程被迫显式轮询 channel ,而在 NIO2情况下,是由操作系统而非应用程序本身启动的。我的测试证实了这一点,但是每种情况都是个别的,因此我想知道详细信息。
4)所有连接器都具有sendfile功能。根据上面的“Choosing tomcat connectors”资源, NIO2 对此进行了模拟。这是什么意思?如果我使用Nginx提供静态文件,则此功能有意义吗?
对我来说,最大的惊喜是所有连接器仍在使用阻塞操作。
官方文档confirms this。
读取请求正文和写入响应 header 和正文正在阻止操作。关于这个,我想在下面说。
接下来,我想了解所有线程如何在真实应用程序中工作。
例如,我有一个4核CPU,我选择 NIO 连接器决定设置以下参数: maxThread =“4”和 maxConnection =“1000”
之后,我启动了VisualVM。这些是我感兴趣的主题:
http-nio-8080-exec [1-4], http-nio-8080-ClientPooler- [0-1]和 NioBlockingSelector.BlockPoller
据我了解, ClientPollers 管理用于读取请求行的非阻塞选择器,并等待保持 Activity 的请求。 NioBlockingSelector.BlockPoller 模拟对请求正文读取/响应写入的阻止。但是为什么要使用阻塞操作?这是否与以下结论相矛盾:“慢速客户端不会使线程停顿”?
在所有这些酝酿的问题之后:
5 )exec线程仅处理了我的请求,或者它们还执行从/到 channel 的读取/写入操作?我回答这个问题,是因为您可以想象这种情况,如果我们有10个传入请求,但是只有4个线程来处理请求。
我有以下假设:
servlet同时处理4个请求,但是仍然可以从套接字读取剩余6个请求的数据(请求 header ,正文)(因为我们在另一个线程中有工作池)。当前4个请求完成时,其余6个请求将已经读取所有数据,并且可以立即进行处理(按队列顺序)。因此,I/O不会空闲。 (但尚未解决 NioBlockingSelector 中的阻塞操作问题)
Servlet处理4个请求,但是我们无法从网络缓冲区读取其他6个请求的数据,仅建立连接。事实证明, exec线程也执行任何读取操作,因此阻止了这些线程处理servlet中的“用户代码”。在这种情况下,我考虑了异步servlet 。我将线程池的大小标识为10。现在,我可以在 Controller 中定义如下长查询:
@GetMapping
public Callable<String> longRunningRequest(){
return () -> {
// long method
return "someView";
};
}
因此,现在 exec线程始终可以读取/写入数据。
但是,如果我只是在连接器配置中定义maxThreads = 4 + 10,会有什么区别?在异步servlet的情况下,似乎我们只是简单地将一个线程交换到了另一个线程。如果对于短请求,我使用 exec线程;对于长时间运行的请求,则使用具有专用线程池的异步servlet 异步操作可能会有好处?
最佳答案
一个问题有很多问题。
简要地:
Are there any advantages of APR before NIO if I don't use TLS on Tomcat?
没有。 APR似乎比NIO的CPU占用率要少一些,但事实并非如此。
If NIO2 uses handler callbacks, does this mean that i need to allocate more threads?
否。您对NIO和NIO2感到困惑。从应用程序的角度来看,所有这些事情都以相同的方式工作。 NIO不会“顺序轮询所有 channel ”。选择器线程实质上会发出
select(2)
,并等待OS通知线程该线程已准备好服务一个或多个 channel 。 NIO2的工作方式相同。Is NIO2 faster than NIO?
不必要。从理论上讲,NIO2应该比NIO“更好”,但是(a)它在目前的形式(2018年2月)上似乎并没有表现出更好的性能或效率,并且(b)比其他任何连接器都新得多,因此可能并非在所有情况下都100%可靠。 YMMV。
All connectors have sendfile functional, [but] NIO2 emulates this.
由于各种原因,NIO2无法使用“true”
sendfile(2)
。客户可以调用它,但是Java将完成工作,而不是OS。Does it make sense [to use
sendfile
], if i [already] use Nginx to serve static files?
否。如果您有提供静态文件的反向代理,则只会降低将这些请求代理到Tomcat,然后使用
sendfile
(是否仿真)将数据返回给客户端的性能。The biggest surprise for me was that all the connectors are still using blocking operations.
为什么那会让你感到惊讶? Servlet API是基于阻塞API(例如
java.io.InputStream
,java.io.OutputStream
等)构建的。如果您想要非阻塞行为,则需要使用Websocket。
关于java - Tomcat连接器具有异步Servlet的工作能力和可伸缩性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48837206/