Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lots of boundedElastic-evictor TIMED_WAITING threads related to form data requests #26263

Closed
Justubborn opened this issue Dec 13, 2020 · 9 comments
Assignees
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) type: regression A bug that is also a regression
Milestone

Comments

@Justubborn
Copy link

I send request to webflux demo server. use springboot version 2.4.1 , create no quantity limit nuboundedElastic-evictor thread and always keep timed waiting status.

test script

ab -n 10000 -c 1000 -T "application/x-www-form-urlencoded" -p test.txt http://127.0.0.1:8080/router/rest/1

controller code

@RestController
@RequestMapping("/router/rest")
public class BaseController {

    @RequestMapping("1")
    public Mono<String> mono(){
        return Mono.just("111");
    }
}

lots of boundedElastic-evictor TIMED_WAITING make memory up obvious.

"boundedElastic-evictor-9998" #10042 daemon prio=5 os_prio=0 cpu=0.00ms elapsed=130.64s tid=0x0000023b82f71dc0 nid=0xe694 waiting on condition  [0x0000008cf91fe000]
   java.lang.Thread.State: TIMED_WAITING (parking)
        at jdk.internal.misc.Unsafe.park([email protected]/Native Method)
        - parking to wait for  <0x000000070aba6988> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.parkNanos([email protected]/LockSupport.java:252)

finally

Switching to version 2.3.7 resolved

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Dec 13, 2020
@rstoyanchev
Copy link
Contributor

Can you provide more details around "no quantity limit nuboundedElastic-evictor thread"? I'm also not sure what you mean by "make memory up obvious".

@rstoyanchev rstoyanchev added status: waiting-for-feedback We need additional information before we can continue in: web Issues in web modules (web, webmvc, webflux, websocket) labels Dec 15, 2020
@Justubborn
Copy link
Author

Justubborn commented Dec 16, 2020

Can you provide more details around "no quantity limit nuboundedElastic-evictor thread"? I'm also not sure what you mean by "make memory up obvious".

after send 1000 request ,the program create 1000 thread name "boundedElastic-evictor" and java memory from 50M increase to 500M

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Dec 16, 2020
@jun-lee
Copy link

jun-lee commented Dec 17, 2020

+1
Spring boot 2.4.0 + Webflux has just the same issue.

@rstoyanchev
Copy link
Contributor

Can you provide more details around "no quantity limit nuboundedElastic-evictor thread"?

I still need this. For example a snippet of how you configure this.

@rstoyanchev
Copy link
Contributor

Actually is it possible to provide a sample app? It's unclear where the boundedElastic use comes from.

@rstoyanchev rstoyanchev added status: waiting-for-feedback We need additional information before we can continue and removed status: feedback-provided Feedback has been provided labels Dec 17, 2020
@Justubborn
Copy link
Author

Actually is it possible to provide a sample app? It's unclear where the boundedElastic use comes from.

Below is all the code, no additional configuration:

@RestController
@RequestMapping("/router/rest")
@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @RequestMapping("1")
    public Mono<String> mono(){
        return Mono.just("111");
    }
}

Below is the thread stack. You can tell from the stack log where boundedElastic came from.

"reactor-http-nio-2@5381" daemon prio=5 tid=0x2a nid=NA runnable
  java.lang.Thread.State: RUNNABLE
	  at reactor.core.scheduler.BoundedElasticScheduler.lambda$static$0(BoundedElasticScheduler.java:75)
	  at reactor.core.scheduler.BoundedElasticScheduler$$Lambda$382.45019084.newThread(Unknown Source:-1)
	  at java.util.concurrent.ThreadPoolExecutor$Worker.<init>(ThreadPoolExecutor.java:619)
	  at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:932)
	  at java.util.concurrent.ThreadPoolExecutor.ensurePrestart(ThreadPoolExecutor.java:1603)
	  at java.util.concurrent.ScheduledThreadPoolExecutor.delayedExecute(ScheduledThreadPoolExecutor.java:334)
	  at java.util.concurrent.ScheduledThreadPoolExecutor.scheduleAtFixedRate(ScheduledThreadPoolExecutor.java:573)
	  at reactor.core.scheduler.BoundedElasticScheduler.start(BoundedElasticScheduler.java:175)
	  at reactor.core.scheduler.Schedulers.newBoundedElastic(Schedulers.java:498)
	  at reactor.core.scheduler.Schedulers.newBoundedElastic(Schedulers.java:454)
	  at org.springframework.http.codec.multipart.DefaultPartHttpMessageReader.<init>(DefaultPartHttpMessageReader.java:77)
	  at org.springframework.http.codec.support.ServerDefaultCodecsImpl.extendTypedReaders(ServerDefaultCodecsImpl.java:72)
	  at org.springframework.http.codec.support.BaseDefaultCodecs.getTypedReaders(BaseDefaultCodecs.java:275)
	  at org.springframework.http.codec.support.BaseCodecConfigurer.getReaders(BaseCodecConfigurer.java:98)
	  at org.springframework.http.codec.support.DefaultServerCodecConfigurer.getReaders(DefaultServerCodecConfigurer.java:27)
	  at org.springframework.web.server.adapter.DefaultServerWebExchange.initFormData(DefaultServerWebExchange.java:143)
	  at org.springframework.web.server.adapter.DefaultServerWebExchange.<init>(DefaultServerWebExchange.java:131)
	  at org.springframework.web.server.adapter.HttpWebHandlerAdapter.createExchange(HttpWebHandlerAdapter.java:243)
	  at org.springframework.web.server.adapter.HttpWebHandlerAdapter.handle(HttpWebHandlerAdapter.java:229)
	  at org.springframework.boot.web.reactive.context.WebServerManager$DelayedInitializationHttpHandler.handle(WebServerManager.java:97)
	  at org.springframework.http.server.reactive.ReactorHttpHandlerAdapter.apply(ReactorHttpHandlerAdapter.java:65)
	  at org.springframework.http.server.reactive.ReactorHttpHandlerAdapter.apply(ReactorHttpHandlerAdapter.java:40)
	  at reactor.netty.http.server.HttpServer$HttpServerHandle.onStateChange(HttpServer.java:628)
	  at reactor.netty.ReactorNetty$CompositeConnectionObserver.onStateChange(ReactorNetty.java:612)
	  at reactor.netty.transport.ServerTransport$ChildObserver.onStateChange(ServerTransport.java:453)
	  at reactor.netty.http.server.HttpServerOperations.onInboundNext(HttpServerOperations.java:510)
	  at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:94)
	  at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	  at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	  at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	  at reactor.netty.http.server.HttpTrafficHandler.channelRead(HttpTrafficHandler.java:208)
	  at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	  at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	  at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	  at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436)
	  at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:324)
	  at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:311)
	  at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:432)
	  at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)
	  at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)
	  at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	  at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	  at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	  at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
	  at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	  at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	  at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
	  at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
	  at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719)
	  at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655)
	  at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581)
	  at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
	  at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
	  at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	  at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	  at java.lang.Thread.run(Thread.java:748)

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Dec 18, 2020
@jun-lee
Copy link

jun-lee commented Dec 18, 2020

Ok, I found the root cause.

DefaultPartHttpMessageReader partReader = new DefaultPartHttpMessageReader();

private Scheduler blockingOperationScheduler = Schedulers.newBoundedElastic(Schedulers.DEFAULT_BOUNDED_ELASTIC_SIZE,

From the above points, a Http request has a Content-Type: "application/x-www-form-urlencoded" causes boundedElastic-evictor-# garbage everytime.

@jun-lee
Copy link

jun-lee commented Dec 18, 2020

A quick workaround would be adding a config.

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
        DefaultPartHttpMessageReader multipartReader = new DefaultPartHttpMessageReader();
        configurer.defaultCodecs().multipartReader(multipartReader);
    }

}

@rstoyanchev rstoyanchev self-assigned this Dec 18, 2020
@rstoyanchev rstoyanchev added type: regression A bug that is also a regression and removed status: feedback-provided Feedback has been provided status: waiting-for-triage An issue we've not yet triaged or decided on labels Dec 18, 2020
@rstoyanchev rstoyanchev added this to the 5.3.3 milestone Dec 18, 2020
@rstoyanchev
Copy link
Contributor

Thanks for the extra details. This is a combination of DefaultPartHttpMessageReader creating resources internally and DefaultServerWebExchange re-creating the codecs per request. We need to make this more efficient and also ensure those resources support a full lifecycle with start and stop.

@rstoyanchev rstoyanchev changed the title lots of boundedElastic-evictor TIMED_WAITING make memory up obvious. Lots of boundedElastic-evictor TIMED_WAITING threads related to form data requests Dec 18, 2020
rstoyanchev added a commit that referenced this issue Jan 5, 2021
- Remove unused clone() code left-over from previous way of cloning.
- Lazy instantiation of ServerCodecConfigurer in
  HttpWebHandlerAdapter since in most cases the configurer instance
  is set externally.

Closes gh-26263
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) type: regression A bug that is also a regression
Projects
None yet
Development

No branches or pull requests

4 participants