57

我想知道tomcat NIO 连接器的内部结构。当我们创建一个实现 CometProcessor 的 servlet 时,线程究竟是如何使用的?每个连接仍然是一个线程吗?

从我读到的,对话是这样的

  1. 客户端连接到 servlet

  2. Servlet 一直挂在连接上,直到有任何数据可供连接的客户端使用

  3. 当数据准备好时,服务器写入 httpResponse 并刷新它。这实际上断开了连接?

  4. 客户端发送另一个请求,服务器再次挂起..

当这种情况不断发生时,使用了多少线程?

4

4 回答 4

60

NIO 和 Comet 完全不相关:您可以混合搭配它们。

由于线程模型,使用 NIO(或 APR)连接器允许您用更少的线程处理更多请求。有关连接器之间的比较,请参阅http://tomcat.apache.org/tomcat-7.0-doc/config/http.html#Connector_Comparison

Comet(和 Websocket)具有完全不同的调度模型,它需要不同的应用程序架构并以不同的方式实现更高的吞吐量。

您在问题中提出的场景是典型的阻塞每个请求一个线程的模型。在第 4 步中,Java BIO 连接器(它是 Tomcat 7 之前的默认连接器)将继续等待现有连接器上的其他请求——对于 keepalive HTTP 请求。如果客户端没有设置Connection:close上一个请求并且没有关闭连接,线程将挂起,直到达到keepalive超时。如果您使用 NIO 连接器,则线程将在发送响应后立即返回线程池,并且您不会在可能永远不会到达的 keepalive 请求上“浪费”线程。

Comet/Websocket 通过将消息传递给专门编写的 servlet(和可选的过滤器)以完全不同的方式工作,并且线程仅在有消息要发送或数据要写入时使用。

更新 2016-08-19

Tomcat 8.5 和 9.0 已经完全放弃了 BIO 连接器。这是因为许多新的 API 和技术(例如 Websocket)需要非阻塞语义,并且在阻塞 API 之上构建非阻塞服务非常非常困难。完成这项工作所需的代码使 Tomcat 代码的其余部分变得非常难看,等等,因此决定完全放弃 BIO 连接器。因此对于 Tomcat 8.5 及更高版本,只有 NIO、NIO2 和基于 APR 的连接器可用。

请注意,同样在 Tomcat 8.5 和 9.0 中,对Comet的支持已被删除。Comet 的使用应该全部替换为更标准的协议 Websocket。

于 2012-06-14T13:31:25.160 回答
4

NIO 使用更少的线程,这意味着 tcp/ip 端口使用更少。

你知道端口是1到65534,所以我们可以说NIO可以达到比BIO更高的TPS(Transactions Per Second)

我测试了协议:HTTP/1.1org.apache.coyote.http11.Http11NioProtocol 相同的 web 项目、相同的主机和相同的 server.xml 但协议。

使用 jmeter 进行测试。

我设置了1000个线程来运行请求,几分钟HTTP/1.1时,主机使用端口超过30000,TPS只有300!

当 org.apache.coyote.http11.Http11NioProtocol 时,使用端口的最大计数永远不会超过 3000,并且 tps 超过 1200!

于 2013-12-03T06:39:40.283 回答
4

添加到这个讨论的后期 - 在阻塞 IO 和异步 NIO 之间的性能比较的上下文中 - 一个很好的阅读是 “写服务器的旧方法是新的”。总而言之,与 NIO 版本相比,每个连接模型的线程性能更好且易于编写——这与流行的看法相反。

于 2016-05-25T12:16:53.683 回答
1

这里有两篇关于 NIO 连接器的好文章,以防有人考虑 Tomcat 中 BIO(请求处理必然接受线程)和 NIO(请求处理被传递到另一个工作线程)之间的差异。

于 2016-07-13T18:23:00.133 回答