在 Jetty 中实现 HTTP2 servlet 的最佳方式是什么?

What is the best way to implement an HTTP2 servlet in Jetty?

我了解 Jetty 中的 HTTP2 主要在连接器、传输和通道级别。

我正在尝试确定哪种组合最适合在客户端和服务器之间传输二进制数据:

  1. 带异步 servlet 的 Jetty HTTP2 服务器 + Jetty HTTP2 客户端
  2. 带同步 servlet 的 Jetty HTTP2 服务器 + Jetty HTTP2 客户端
  3. 带异步 servlet 的 Jetty HTTP2 服务器 + Netty HTTP2 客户端
  4. GRPC 客户端和服务器(默认都是基于 Netty 的)

详情:

我想向我的客户端发送二进制数据,我希望连接为 non-blocking/async。并发客户端请求的数量可能很高,服务器可能需要几秒钟(有时)才能响应某些请求。

每个响应都是一小块二进制数据。如果我可以直接发送 Netty 的 ByteBufs 作为响应而不是复制到 byte[]ByteBuffer,我会很高兴,但这与这个特定问题没有直接关系。

方法 #4 不是我最喜欢的,因为 ProtoBuf wrapping (link) limitation (link)

Jetty 参考资料:

免责声明,我是 Jetty HTTP/2 维护者。

鉴于您有大量客户端并且处理可能需要几秒钟,我建议使用选项 1 - 异步 servlet 和 Jetty HTTP/2 客户端。

使用 "async servlet" 你有 2 种风格:1) 带阻塞的异步处理 I/O,或 2) 异步处理 + 异步 I/O.

使用HttpServletRequest.startAsync().

触发Servlet异步处理

Servlet 异步 I/O 由 ReadListenerWriteListener 分别与 ServletInputStreamServletOutputStream 触发。

您肯定需要异步处理,因为您有大量的客户端和以秒为单位的处理 - 这将优化服务器线程的使用。

是否使用 async I/O 可能应该被衡量,因为你有小的二进制响应。 阻塞 I/O 编码和调试要容易得多,而异步 I/O 编码和调试肯定更复杂。异步 I/O 当您有大量内容和可能会阻塞 TCP 连接的慢速客户端时,它真的很出色。

如果您想完全异步,请使用异步 I/O。如果您可以容忍一些阻塞以换取更简单的代码,请继续阻塞 I/O。 值得重复,在这两种情况下 - 异步 I/O 或阻塞 I/O - 你想使用异步处理。

关于复制数据的问题,如果你愿意往下投到Jetty类,直接在ServletOutputStream子类写一个ByteBuffer就可以避免复制,参见 this example

最后,通过 Jetty 客户端,您可以使用 high-level HttpClient 和 HTTP/2 传输,详见 here。好处是 high-level API 只处理 HTTP 概念,而不是使用处理 HTTP/2 帧、流等的 low-level HTTP2Client

报告您最终选择的内容,以及结果如何!