maa*_*nus 19 java asynchronous servlets
我的Servler花了很多时间阅读request.getInputStream()和写作response.getOutputStream().从长远来看,这可能是一个问题,因为它阻止一个线程只是读/写字面上每秒几个字节.(*)
我从不对部分请求数据感兴趣,处理不应在请求完全可用之前启动.同样的回应.
我想,异步IO会解决它,但我想知道什么是正确的方法.也许一个servlet 在收集完整个输入之后用一个包装,使用和调用链式servlet 来Filter替换它?ServletInputStreamByteArrayInputStreamrequest.startAsync
请注意,我的意思是避免在慢速servlet流上浪费线程.这与startAsync避免浪费线程等待某个事件的情况不同.
是的,目前这是一个不成熟的优化.
我当前的输入流读取方法没有什么有趣的,但在这里你是:
private byte[] getInputBytes() throws IOException {
ServletInputStream inputStream = request.getInputStream();
final int len = request.getContentLength();
if (len >= 0) {
final byte[] result = new byte[len];
ByteStreams.readFully(inputStream, result);
return result;
} else {
return ByteStreams.toByteArray(inputStream);
}
}
Run Code Online (Sandbox Code Playgroud)
这就是全部,它在数据不可用时阻止; ByteStreams来自番石榴.
正如答案明确指出的那样,在不浪费线程的情况下使用servlet流是不可能的.servlet体系结构和通用实现都没有公开任何允许说"缓冲整个数据并仅在收集所有内容时给我打电话"的内容,尽管他们使用NIO并且可以做到.
原因可能是通常使用像nginx这样的反向代理,这可以做到.nginx默认执行此缓冲,直到两年前才关闭它.
鉴于许多负面答案,我不确定,但它看起来像我的目标
避免在慢速servlet流上浪费线程
实际上是完全支持的:从3.1开始,ServletInputStream.html#setReadListener似乎就是为了这个.分配用于处理的线程Servlet#Service最初调用request.startAsync(),附加侦听器并通过简单地返回返回池service.侦听器实现onDataAvailable(),当可以无阻塞地读取时调用它,添加一段数据并返回.在onAllDataRead(),我可以对收集的数据进行整个处理.
有一个例子,它如何用Jetty完成.它似乎也涵盖了非阻塞输出.
(*)在日志文件中,我可以看到花费在读取输入(100字节标题+ 100字节数据)上花费8秒的请求.这种情况很少见,但它们确实发生了,尽管服务器大多处于闲置状态.所以我猜,它是一个非常糟糕的连接上的移动客户端(我们的一些用户从连接不良的地方连接).
Bal*_*usC 12
HttpServletRequest#startAsync()对此没用.这只适用于推动网络套接字和良好的"上网"等内容.此外,JSR356 Web Socket API建立在它之上.
您的具体问题已被理解,但这绝对无法从servlet上解决.由于容器已经将当前线程专用于servlet请求,直到请求体完全读取到最后一位,即使它最终被新生成的读取,你最终只会浪费更多线程.异步线程.
要保存线程,您实际上需要一个支持NIO的servletcontainer,并在必要时启用该功能.使用NIO,单个线程可以处理与可用堆内存允许的TCP连接数相同的TCP连接,而不是每个TCP连接分配一个线程.然后,在您的servlet中,您根本不需要担心这个微妙的I/O任务.
几乎所有现代servlet容器都支持它:Undertow(WildFly),Grizzly(GlassFish/Payara),Tomcat,Jetty等.有些默认启用它,其他需要额外配置.只需使用关键字"NIO"参考他们的文档.
如果您实际上也想要保存servlet请求线程本身,那么您基本上需要退后一步,删除servlet并在现有NIO连接器(Undertow,Grizzly,Jetty,等等).
| 归档时间: |
|
| 查看次数: |
953 次 |
| 最近记录: |