java - Jetty 和其他容器如何在遵守 Servlet 规范的同时利用 NIO?

标签 java servlets jetty nio nonblocking

我是 NIO 的新手,我正在尝试弄清楚 Jetty 如何利用 NIO。

我对传统 servlet 容器如何使用 Blocking IO 服务请求的理解如下:

  1. 请求到达
  2. 分配一个线程来处理请求并调用 servlet 方法(doGet 等)
  3. Servlet 方法被传递一个 InputStreamOutputStream
  4. servlet 方法从 InputStream 读取并写入 OutputStream
  5. InputStreamOutputStream 基本上与底层 Socket
  6. 的各自流相关联

使用 NIO 连接器有什么不同?我的猜测是这样的:

  1. 请求到达
  2. Jetty 使用 NIO 连接器并异步缓冲整个请求
  3. 读取请求后,将缓冲区完全包装在 InputStream
  4. 创建一个空的响应缓冲区(包装在 OutputStream 中)
  5. 分配一个线程并调用处理上述包装流的 servlet 方法(doGet 等)
  6. Servlet 方法写入包装(缓冲)的响应流并从 servlet 方法返回
  7. Jetty 使用 NIO 将响应缓冲区内容写入底层 SocketChannel

从 Jetty 文档中,我发现了以下内容:

SelectChannelConnector - 此连接器使用具有非阻塞线程模型的高效 NIO 缓冲区。 Jetty 使用 Direct NIO 缓冲区,并且只将线程分配给有请求的连接。同步模拟 servlet API 的阻塞,请求处理结束时任何未刷新的内容都是异步写入的。

我不确定我是否理解同步模拟 servlet API 的阻塞 是什么意思?

最佳答案

你没有完全正确。当 jetty 使用 NIO 连接器(并且 9 只支持 NIO)时,它的工作原理如下:

  1. 空闲状态为几个线程(1-4 个,取决于 # 内核)调用选择器,寻找 IO Activity 。这已扩展到 Jetty 上超过 1,000,000 个连接。
  2. 选择器看到IO Activity 时,它调用连接上的句柄方法,该方法要么:

    • 其他东西已经注册它被阻塞等待此连接的 IO,所以在这种情况下,选择器只会唤醒被阻塞的人。
    • 否则会调度线程来处理连接。
  3. 如果一个线程被调度,那么它将尝试读取连接并解析它。现在发生的情况取决于连接是 http、spdy、http2 还是 websocket。

    • 对于 http,如果请求 header 完整,则线程继续调用对请求的处理(最终到达 servlet)而不等待任何内容。
    • 对于 http2/spdy 需要另一个调度,但请参阅列表中关于 Eat-What-You-Kill 策略的讨论:http://dev.eclipse.org/mhonarc/lists/jetty-dev/msg02166.html
    • 对于 websocket,调用消息处理。
  4. 一旦一个线程被分派(dispatch)给一个 servlet,它看起来就像 servlet IO 是阻塞的,但是在 HttpInputStream 和 HttpOutputStream 的级别之下,所有的 IO 都是与回调异步的。阻塞 API 使用特殊的阻塞回调来实现阻塞。这意味着如果 servlet 选择使用异步 IO,那么它只是绕过阻塞回调,或多或少地直接使用异步 API。

  5. servlet 可以使用 request.startAsync 挂起,在这种情况下,分派(dispatch)的线程会返回到线程池,但关联的连接不会被标记为对 IO 感兴趣。可以执行异步 IO,但需要 AsyncContext 事件来重新分配线程或在异步周期完成后重新注册 IO Activity 的连接。

这个 View 由于 http2 和 spdy 有点复杂,它们是多路复用的,因此它们可能涉及额外的调度。

任何不分派(dispatch)的 HTTP 框架都可以在基准代码中运行得非常快,但是当面对一个真正的应用程序时,它可以做一些愚蠢的事情,比如阻塞数据库、文件系统、REST 服务等......然后就是缺乏分派(dispatch)意味着一个连接可以保持系统上的所有其他连接。

有关 jetty 如何处理异步和调度的更多信息,请参阅:

关于java - Jetty 和其他容器如何在遵守 Servlet 规范的同时利用 NIO?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25195128/

相关文章:

java - 按下按钮时播放声音-android

java - 从远程服务器读取并连续写入远程服务器

Java HttpURLConnection获取所有内容包括css、img等

tomcat - java.io.FileNotFoundException :/usr/lib/jvm/java-7-openjdk-i386/jre/lib/ext/javax. mail.jar(权限被拒绝)

http - Websocket 情况 - 在端口 80 或 443 上,websocket 消息无法通过

forms - FORM 范围总是空的? URL 范围可以吗?

java - 使用权限运行小程序的 Eclipse 应用程序

google-app-engine - 我想从 servlet 向 HttpServletResponse 添加一些纯文本内容和两个 header

java - Jetty 9 托管具有多个 SSL 证书的多个虚拟主机

java - Java PreparedStatement.setBytes 与 mysql 语法错误