-
Notifications
You must be signed in to change notification settings - Fork 38.5k
WebFlux with Java 11 HttpClient unexpected slow performance comparing with WebClient #22333
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
Comments
Are you doing all this on localhost? That skews the results quite a bit since client and server compete for the same hardware and CPU cycles, but there is a limited number of cores. In the case of WebClient both server and client likely share resources so the number of threads is probably closer to the number of cores for the machine as it should be with event loop concurrency. For HttpClient it's allocating 10 threads which I'm guessing is much higher than number of cores and that's in addition to the ones used for the server. Try lowering the number of threads closer to the number of cores to confirm. |
Hi @rstoyanchev This is the memory with single thread for Java Http Client.
For WebClient
For Tomcat and Java HttpClient
So for Tomcat and Java HttpClient GC takes 5-10%CPU |
Tested with Apache Http Client and it works perfect(the same performance as with WebClient). |
I've tried to locally profile your sample application with Yourkit - doing that locally is flawed for sure, but I'd expect to find similar things still. I did not reproduce several of your findings.
WebFlux is still 40% faster than Spring MVC in my local benchmark.
In my local benchmark, GC CPU time is almost flatlining at 0-1% for all variants. I do see that the As seen in the
My current understanding is that clients have different strategies when it comes to buffer allocation, and some of those might behave better than others under high load or high concurrency. It looks like "EC2 t2.micro" instances have 1GB of memory and only one vCPU - I guess a lot of allocations on the heap and a single CPU is not helping the GC threads and those are competing with the application. Also, this might be even pushed further if JMeter is creating a lot of concurrent connections - this will push the With that in mind, I don't think we can do anything in Spring Framework to improve this situation; maybe you could try and run those benchmarks on servers with a bit more resources? |
Hi @bclozel, are you sure that you tested it with Tomcat? I've updated the sample project (added maven profiles for servlet and webflux and introduced Apache Http Client for comparison). You are right, EC2 t2.micro has 1 CPU. And I understand the GC problem for single core node. But the question why with Tomcat and servlet we don't have GC issue? So I prepared an article about it. You can see all the information here. https://medium.com/@filia.aleks/microservice-performance-battle-spring-mvc-vs-webflux-80d39fd81bf0 Locally on i7 Core, I also don't see the problem, only for small ec2 node. Do you have ability to test it for single core node? |
I find the 3 conclusions at the end of your article quite misleading.
This might be true in your case but your article should make obvious that you're running on a single core, 1GB RAM server instance. This is very unusual for a performance benchmark and skews the results. This is interesting because it shows how systems behave wrt concurrency with limited resources - but it's almost pathological.
At this point, we don't know why you're seeing such results. So this sentence could read "Java 11 Http Client is not friendly with Netty" or "Java 11 Http Client doesn't work well with non-blocking servers", or "this combination of runtime models doesn't work well when you only have one core and little RAM". Also, your benchmark is not showing latency stats - with limited resources, the 99% percentile might be a disaster and optimizing for throughput might be misguided here. I'm closing this issue now as it seems this is more about the benchmark setup and runtime models rather than a performance problem in WebFlux. Thanks! |
Hi @bclozel. I agree with your comments. I see that it's not a Spring problem. But 1 CPU and 1 GB is a quite popular setup for dockerized microservices on Kubernetes and AWS ECS cluster. That is why I made benchmarks for this setup. Thank you! |
The tests above are running with delay=1 which is treated as 1 millisecond, or am I missing something? This is also unusual. In a realistic app the latency would be higher, and it's latency that brings out the benefits of asynchronous handling. Brian provided a lot of pointers for further investigation on the JDK 11 client. Specifically I would dig into the buffer allocation strategies and understand the options and trade-offs since you're suspecting allocation issues. I would also suggest making client benchmark tests independent of Spring MVC of Webflux and compare the performance of JDK 11 client to the WebClient or the Apache client, and if necessary use the appropriate Java mailing list to ask questions. |
@rstoyanchev , you are right delay=1 means 1ms delay. But as you can see here https://user-images.githubusercontent.com/10498901/52384210-86b0cd80-2a8d-11e9-825e-5307957eba0b.png |
I have switched from OkHTTP 3.x to Java 15 http cllient and performance decreased significantly. My use case involves downloading many (~50000) average sized binary files (100s kb's to 10's megabytes) from the https in parallel threads. The performance degradation is about 50%. Does anyone meet such problems? |
Environment: Spring Boot 2.1.2.RELEASE, Java 11(OpenJDK/Oracle)
So, I have RestConrtoller that sends an incoming request to another Rest service and returns the result back to clients.
So I compared WebClient with Java 11 HttpClient and I see an unexpected slow performance (looks like due to high GC usage) for Java 11 HttpClient.
Jmeter shows that with Java 11 HttpClient we have in 2 times less throughput than with WebClient. The problem cannot be in Java HttpClient because I tested the same stuff with Spring MVC and it has the same performance as with WebClient.
All code you can see here https://github.com/Aleksandr-Filichkin/spring-mvc-vs-webflux.
JMeter files for the test also are added.
I think the problem in memory because I see high GC usage for HttpClient comparing with WebClient.

So getUserUsingWithCF with Spring MVC works in two times faster than getUserUsingWebfluxJavaHttpClient with WebFlux
The text was updated successfully, but these errors were encountered: