Comparing with non java technologies #712
Replies: 5 comments 12 replies
|
Just FYI we have now the option to extract if the excess of RSS belong to heap or off heap so to tune it accordingly, see https://bugs.openjdk.org/browse/JDK-8318636 I have still few concerns re different aspects:
The very first point is quite important as different runtimes react differently to CPU saturation (GCs are mostly background and exploit batching!); in addition to that, we don't know yet if the CPU saturation too apply equally to all of them since they have different peak tps too. |
|
One qq @vsevel did you measure the peak RSS? And last but not least. |
|
the optimal heap for quarkus3-native is 64m (was 48 for quarkus3-virtual). and I get a density of around 14 req/s/Mb, better than quarkus jvm (8 req/s/Mb), but smaller than go (39) and rust (78). |
|
Hi @vsevel , very interesting I love this idea of a broader comparison. I've had it in mind for a long time that we should compare ourselves with a broader set of languages and frameworks, which is why I've been playing quite a bit with the Techempower benchmarks in the past: it resonated with me that there would be such a variety of highly tuned submissions; alas the benchmarks were also quite unrealistic, and are now no longer maintained. And it was fun. It's tempting to reuse this particular benchmark here, but the original goal and intent is a bit different and such differences do alas have an impact: it was meant to compare with Spring with a focus on easy migrations, aka we'd disallow any form of tuning as it needed to showcase the ability of Quarkus to perform better in an out of the box configuration. It was also meant to be transparent about the figures we post on the homepage. I do agree with you that Quarkus should be measured vs Rust and similar stacks - but we need to be careful with the perspectives. As an engineer I do want to compare and get it "as close as possible" but realistically while I like a challenge it will be hard to beat it in terms of minimal size - just the spec requirements of the JVM and some of its frameworks won't make it possible. So Quarkus can hopefully approach its efficiency and maintain a better total balance on ROI because the language has such a fantastic ecosystem and tooling, but this needs to be put in perspective and there's an aspect of subjectivity; we can't objectively measure aspects such as maintainability, availability of enteprise support and integrations, etc.. so there's a risk of such metrics getting misinterpreted or misused. We need to do such comparisons as part of engineering in the open, to keep us improving, but can't claim them to be comprehensive benchmarks. In particular our frameworks, and the JVM as well, do come out of the box with signicant bias towards large multi-core machines an plenty of memory. I believe we might be able to approach the efficiency of rust - with some work and collaborations within the ecosystem - but only if we allow tuning to happen in such a test, which is not allowed in this benchmark at the moment. We'd probably need to also introduce (and document) several more low level flags, perhaps a profile, to let the build system know that we're aiming for "small" over raw throughput. Any thoughts on this? I'd like to help - I've recently played with developing a new small, native-image based Quarkus app and had some fun making it more efficient - but to do this I've had to use (and in some cases introduce) several low level flags. We could see if these could be sane enough to be made more generally available, either as an advanced tuning guide, or as some sort of profile system. But again - this might close the gap with rust somewhat while maintaining access to our most advanced components, but I don't think it will beat it in terms of minimal RSS. It might also need to compromise on some "nice to haves" that our typical user is expecting; for example in my experiments I push many more flags to be build-time-only. I think that's necessary but it's been very unpopular for Java users coming from different platforms. |
|
Thanks for sharing this detailed evaluation. The focus on density (throughput per MB of memory) as the primary metric makes a lot of sense for auto-scaling use cases, where resource efficiency can be more important than absolute peak throughput. The comparison between Quarkus, Spring Boot, Go, Rust, and Node.js is particularly interesting. The results for Rust (115 tps/MB) and Go (63 tps/MB) are quite compelling compared with the ~22 tps/MB you're seeing from the Quarkus JVM/native workloads. The build-time comparison is also noteworthy, especially Go at 44 seconds and Rust at 188 seconds versus roughly 300 seconds for GraalVM compilation. I also agree that the absolute numbers should be interpreted with some caution given the differences in the test environments. Running the same workloads on a more controlled and identical machine setup would make the comparison much stronger, particularly for memory consumption, vertical scalability, and the 1-core vs 2-core results. A few additional things I'd be interested in seeing: Warm-up behaviour: memory and throughput after the first request versus after the application has stabilised. The heap-sizing results on Java are also useful. The fact that reducing the heap doesn't materially change Node.js memory consumption suggests that the memory footprint there is being driven by factors other than the configured heap, so it would be worth looking at the runtime baseline/native allocations as well. Overall, I think the results are valuable even if the environment isn't perfectly controlled. They provide a useful direction for the evaluation, and the Go/Rust results are strong enough to justify considering them alongside the traditional Spring Boot vs. Quarkus comparison rather than treating those two as the only candidates. I'd definitely be interested in seeing the results after the Node.js and Go implementations have been reviewed and the benchmark is repeated on a controlled environment. |
Uh oh!
There was an error while loading. Please reload this page.
I am working on an evaluation of different technologies in the context of providing recommendations for our auto-scaling use cases.
I have forked this repo, and added 3 new runtimes:
nodejsgorustI ran the different tests with 1 and 2 cores.
Since I am looking at the auto-scaling use case, the primary metrics I am interested in are (in order):
all runs are archived, and I maintain a synthesis report:
https://github.com/TechAndOperations/spring-quarkus-perf-comparison/blob/feature/density/results/README.md
Since I am interested in density, I tried squeezing the heap on java workloads. I tried
512,256,128,96,64,48. And I would retain the best run for each runtime java. For instance I get the best density forquarkus3-nativeat96 Mb, and64 Mbforquarkus3-virtual. I tried to do that as well onnodejs, but I did not see any change in memory usage.I compared the ratio you get with 4 cores in your lab, and the ones I get in my environment. It is not too far off, but differences of amplitude appear smaller in my environment. Results quality would benefit from being executed in a more controlled machine setup.
The differences between the runtimes have been documented (mainly regarding observability and orm strategy).
If I put aside weak performances on
nodejsandspring4-native, I was impressed with the results ofrustandgo. In absolute throughput, it is true thatquarkus3-virtualbeats everybody at 7032 req/s, but it consumes499 Mbof RSS, whenrustconsumes just21 Mband gets2322 req/s.gogets a better throughput with more memory, but far belowquarkus3(jvm or graalvm).As a result, I can get a much higher density on
rust(115 tps/Mb) andgo(63 tps/Mb) compared toquarkus3jvm or native (around22 tps/Mb).Other interesting metric, I am getting good results on build times on 2 cores: 44 secs on
go, 188 secs onrust, when a graalvm compilation takes around 300 secs.I know quarkus/springboot are seen to be the main competitors to each other. But I would love to see other technologies to be considered as well, specially
gothat shares some similarities with the JVM (e.g. a GC), compiles extremely fast, and gets 3 times the density of quarkus.We are in the process of reviewing internally the code for
nodejsandgo. I know our environment is not ideal, but hopefully the tests still have some value. Do not hesitate to comment on the application code or the methodology.cc @franz1981
All reactions