Java 弹簧靴&x2B;tomcat 8.5+;mongoDB,AsyncRequestTimeoutException
我创建了一个SpringBootWeb应用程序,并将其部署到tomcat容器中。 应用程序使用异步连接连接到Java 弹簧靴&x2B;tomcat 8.5+;mongoDB,AsyncRequestTimeoutException,java,spring,mongodb,spring-boot,tomcat8.5,Java,Spring,Mongodb,Spring Boot,Tomcat8.5,我创建了一个SpringBootWeb应用程序,并将其部署到tomcat容器中。 应用程序使用异步连接连接到mongoDB。为此,我使用了mongodb驱动程序异步库 启动时一切正常。但一旦负载增加,DB连接中就会出现以下异常: org.springframework.web.context.request.async.AsyncRequestTimeoutException: null at org.springframework.web.context.request.asy
mongoDB
。为此,我使用了mongodb驱动程序异步库
启动时一切正常。但一旦负载增加,DB连接中就会出现以下异常:
org.springframework.web.context.request.async.AsyncRequestTimeoutException: null
at org.springframework.web.context.request.async.TimeoutDeferredResultProcessingInterceptor.handleTimeout(TimeoutDeferredResultProcessingInterceptor.java:42)
at org.springframework.web.context.request.async.DeferredResultInterceptorChain.triggerAfterTimeout(DeferredResultInterceptorChain.java:75)
at org.springframework.web.context.request.async.WebAsyncManager$5.run(WebAsyncManager.java:392)
at org.springframework.web.context.request.async.StandardServletAsyncWebRequest.onTimeout(StandardServletAsyncWebRequest.java:143)
at org.apache.catalina.core.AsyncListenerWrapper.fireOnTimeout(AsyncListenerWrapper.java:44)
at org.apache.catalina.core.AsyncContextImpl.timeout(AsyncContextImpl.java:131)
at org.apache.catalina.connector.CoyoteAdapter.asyncDispatch(CoyoteAdapter.java:157)
我正在使用以下版本的软件:
弹簧靴->1.5.4.1释放
Tomcat(作为独立二进制文件安装)->apache-Tomcat-8.5.37
Mongo DB版本:v3.4.10
mongodb驱动程序异步:3.4.2
一旦我重新启动tomcat服务,一切都开始正常工作
请帮忙,这个问题的根本原因是什么
注意:我正在使用DeferredResult
和CompletableFuture创建异步RESTAPI
我还尝试在应用程序中使用spring.mvc.async.request timeout
,并在tomcat中配置了asynTimeout
。但是仍然会出现相同的错误。很明显,Spring正在超时您的请求,并抛出AsyncRequestTimeoutException
,这会将503返回给您的客户端
现在的问题是,为什么会发生这种情况?有两种可能性
这些都是合法的暂停。您提到只有当服务器上的负载增加时才会看到异常。因此,您的服务器可能无法处理该负载,并且其性能已下降到某些请求无法在Spring超时之前完成的程度
超时是由于您的服务器由于编程错误而无法发送对异步请求的响应而导致的,该请求一直保持打开状态,直到Spring最终将其超时。如果您的服务器不能很好地处理异常,这种情况很容易发生。如果您的服务器是同步的,那么在异常处理方面可以有点马虎,因为未处理的异常将传播到服务器框架,服务器框架将向客户端发送响应。但是,如果在某些异步代码中无法处理异常,那么该异常将在其他地方被捕获(可能在某些线程池管理代码中),并且该代码无法知道有异步请求正在等待引发异常的操作的结果
在不了解更多应用程序的情况下,很难了解可能发生的情况。但有些事情你可以调查
首先,尝试寻找资源枯竭
- 垃圾收集器是否一直在运行
- 是否所有CPU都固定在100%
- 操作系统交换频繁吗
- 如果数据库服务器位于单独的计算机上,该计算机是否显示资源耗尽的迹象
- 有多少连接打开到数据库?如果有连接池,它是否已达到最大值
- 有多少线程正在运行?如果服务器中有线程池,它们是否已达到最大值
如果某件事情处于极限,那么可能是瓶颈导致您的请求超时
尝试将spring.mvc.async.request timeout
设置为-1,看看会发生什么。你现在是不是每一个请求都会得到响应,只是很慢,还是有些请求似乎永远挂起?如果是后者,则强烈表明您的服务器中存在错误,导致它无法跟踪请求并发送响应。(如果设置spring.mvc.async.request timeout
似乎没有效果,那么接下来您应该调查的是用于设置配置的机制是否实际工作。)
在这些情况下,我发现一个有用的策略是为每个请求生成一个唯一的ID,并在服务器每次发出异步调用或从异步调用接收响应时,以及在异步处理程序中的各个检查点,将ID与一些上下文信息一起写入。如果请求丢失,您可以使用日志信息来确定请求ID以及服务器上一次对该请求执行的操作
类似的策略是将每个请求ID保存到一个映射中,其中的值是一个对象,该对象跟踪请求启动的时间以及服务器上次对该请求执行的操作。(在这种情况下,您的服务器在每个检查点更新此映射,而不是写入日志,或者另外写入日志。)您可以设置筛选器以生成请求ID并维护映射。如果您的筛选器看到服务器发送5xx响应,则可以从映射中记录该请求的最后一个操作
希望这有帮助 异步任务安排在队列(池)中,队列(池)根据分配的线程数并行处理。并非所有异步任务都同时执行。他们中的一些人在排队。在这样的系统中,获取AsyncRequestTimeoutException是正常行为
如果您正在使用无法在压力下执行的异步任务填充队列。增加超时时间只会延迟问题。你应该把注意力放在问题上:
减少异步任务的执行时间(通过各种优化)。这将放松异步任务的池。它显然需要编码
增加分配的CPU数量,以便能够更高效地运行并行任务
增加为驱动程序的执行器提供服务的线程数
Mongo异步驱动程序正在使用AsynchronousSocketChannel
或Netty(如果在类路径中找到Netty)。为了增加为异步通信提供服务的工作线程的数量,您应该使用:
MongoClientSettings.builder()
.streamFactoryFactory(NettyStreamFactoryFactory(io.netty.channel.EventLoopGroup eventLoopGroup,
io.netty.buffer.ByteBufAllocator allocator))
.build();
其中eventLoopGroup将是io.netty.channel.nio.NioEventLoopGroup(int-nThreads))
在NioEventLoopGroup上,您可以设置为异步通信服务的线程数
了解更多关于Nett的信息