multithreading - Tomcat响应过程中有1000多个线程 block

标签 multithreading spring-boot embedded-tomcat-8

问题优先:

当并发增加时,我的服务响应时间会增加。我在tomcat响应客户端的步骤中发现了1000多个线程块。但是我不知道如何解决。

背景:

我的服务是一个嵌入了tomcat的Spring启动项目。 (tomcat-embed-core-8.5.23)

我的实验是使用JMeter作为客户端,创建2000个线程将请求发送到我的服务10轮(总共20000个请求)。在我提供服务后,有一个 stub 服务可以对每个请求在2秒的延迟内做出响应。 (即JMeter(2000线程)=> 我的服务 => stub 服务器)

实验数据

  • 在我的服务中,我设置为“server.tomcat.max-threads = 2000”。因此,有2000多个线程名为“http-nio-8080 *”
  • 结果是,最大响应时间> 30 s。这是从CLI复制的,

    摘要= 20000 in 00:01:23 = 241.7/s平均:6890最小值:2288最大值:31158错误:0(0.00%)

  • 最小响应时间(2288毫秒)符合预期(由于 stub 服务器的成本为2000毫秒)。但是最大响应时间(31158 ms)太长。我分析了jstack日志。同一锁上有1121个线程被阻塞。 (我附加了堆栈内容之一。我认为这是我对JMeter的服务响应的时间点。但是不幸的是,有一个SynchronizedStack阻止了1000多个线程)

    我有证据表明,锁是响应时间的真正杀手。 9秒后,在另一个jstack日志中,同一锁上仍然有1058个线程锁。
    "http-nio-8080-exec-3988" #4038 daemon prio=5 os_prio=0 tid=0x00007fdec045c800 nid=0x1050 waiting for monitor entry [0x00007fdb6c94e000]
       java.lang.Thread.State: BLOCKED (on object monitor)
                    at org.apache.tomcat.util.collections.SynchronizedStack.pop(SynchronizedStack.java:75)
                    - waiting to lock <0x00000000dac7afd0> (a org.apache.tomcat.util.collections.SynchronizedStack)
                    at org.apache.tomcat.util.net.NioBlockingSelector.write(NioBlockingSelector.java:89)
                    at org.apache.tomcat.util.net.NioSelectorPool.write(NioSelectorPool.java:157)
                    at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.doWrite(NioEndpoint.java:1267)
                    at org.apache.tomcat.util.net.SocketWrapperBase.doWrite(SocketWrapperBase.java:670)
                    at org.apache.tomcat.util.net.SocketWrapperBase.flushBlocking(SocketWrapperBase.java:607)
                    at org.apache.tomcat.util.net.SocketWrapperBase.flush(SocketWrapperBase.java:597)
                    at org.apache.coyote.http11.Http11OutputBuffer.flushBuffer(Http11OutputBuffer.java:581)
                    at org.apache.coyote.http11.Http11OutputBuffer.flush(Http11OutputBuffer.java:272)
                    at org.apache.coyote.http11.Http11Processor.flush(Http11Processor.java:1560)
                    at org.apache.coyote.AbstractProcessor.action(AbstractProcessor.java:283)
                    at org.apache.coyote.Response.action(Response.java:173)
                    at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:317)
                    at org.apache.catalina.connector.OutputBuffer.flush(OutputBuffer.java:284)
                    at org.apache.catalina.connector.CoyoteOutputStream.flush(CoyoteOutputStream.java:118)
                    at sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:297)
                    at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:141)
                    - locked <0x00000000fe000000> (a java.io.OutputStreamWriter)
                    at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:229)
                    at org.springframework.util.StreamUtils.copy(StreamUtils.java:119)
                    at org.springframework.http.converter.StringHttpMessageConverter.writeInternal(StringHttpMessageConverter.java:106)
                    at org.springframework.http.converter.StringHttpMessageConverter.writeInternal(StringHttpMessageConverter.java:41)
                    at org.springframework.http.converter.AbstractHttpMessageConverter.write(AbstractHttpMessageConverter.java:227)
                    at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:247)
                    at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:174)
                    at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:81)
                    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:113)
                    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
                    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
                    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
                    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)
                    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
                    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
                    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
                    at javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
                    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
                    at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
                    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
                    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
                    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
                    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
                    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
                    at org.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.java:55)
                    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
                    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
                    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
                    at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:110)
                    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
                    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
                    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
                    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
                    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
                    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
                    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
                    at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:108)
                    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
                    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
                    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
                    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81)
                    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
                    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
                    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
                    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
                    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
                    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
                    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
                    at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:106)
                    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
                    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
                    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
                    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
                    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
                    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
                    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
                    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
                    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
                    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
                    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803)
                    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
                    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
                    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459)
                    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
                    - locked <0x00000000e1a59188> (a org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper)
                    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
                    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
                    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
                    at java.lang.Thread.run(Thread.java:748)
    
       Locked ownable synchronizers:
                    - <0x00000000df55e210> (a java.util.concurrent.ThreadPoolExecutor$Worker)
    

    最佳答案

    您错误地允许tomcat过量使用。

    首先,将tomcat执行器线程限制为大约100或200个最大值。
    实际上,任何jvm中的线程数量都不应超过200,除非您真的知道自己在做什么,并且有99%的线程在等待(不阻止监视器进入)。

    然后,限制tcp SYN队列的长度(serversocket接受队列),以确保在建立太多连接时不接受所有jmeter连接。

    从严重受限的线程开始,并仅在网络带宽和CPU都闲置时才增加线程数,即使在这种情况下,只要响应时间不增加,就增加线程数。

    关于multithreading - Tomcat响应过程中有1000多个线程 block ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49978938/

    相关文章:

    multithreading - 线程总是在同一个核心上运行吗?

    java - Spring Boot 中的 RabbitMQ 有什么问题

    java - 如何在 Jackson 的注释 JSON 属性中使用正则表达式

    java - 注释顺序在 SB 应用程序中是否重要?

    spring-boot - 从 Spring Boot 的嵌入式 Tomcat 提供日志文件

    objective-c - scheduleInRunLoop - 线程网络连接

    c# - 在另一个线程中调用函数 C#

    java - SpringBoot 2.1.3 : Embedded Tomcat Logging

    tomcat - Spring-boot,tomcat-embedded——如何定义catalina.properties?

    multithreading - 并发: Processes vs Threads