-
Notifications
You must be signed in to change notification settings - Fork 38.1k
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
Improve Spring AOP performance for methods without specific advice #32104
Comments
Is |
It's the cache lookup. In response to a request, the application sends ~300 background tasks to the thread pool, each of which starts to access proxied beans. This generates a cpu micro-spike that makes the
Most are request-scoped singletons. |
Thanks for the insight. I'll try to revisit our interceptor delegation arrangement there ASAP, maybe there is something we can auto-optimize in such a scenario when we know there is no specific advice for the entire object, in particular for scoped proxies. |
Actually, for scoped proxies, there is always the |
Right, we do not use that. |
As a side note: For maximum dispatching performance, it's advisable to use Generally, CGLIB dispatching can be optimized through For interface-based JDK proxies, the optimization for an empty chain is minor since it just uses slightly more efficient dispatching then. There is no way to bypass So we could specifically handle introduction advice in Which leaves us with a situation where |
It turns out that a straightforward approach is to share the cached interceptors list for the entire Advised instance if there is no method-specific Advisor (which is the case for scoped proxies). This bypasses the ConcurrentHashMap lookup and replaces it with direct field access for such arrangements, hopefully adequately improving performance for your scenario. |
A recent improvement in the same area (specific to JDK proxies), also affecting AdvisedSupport cache fields: #30499 |
Profiling data shows the lookup is 98% of the difference between Two questions:
|
Technically there is advice here (the This is pushed to As for an official backport, this might be technically feasible but I'd really like to give this a road test in 6.1.4 first. We do not usually backport that kind of change proactively since we tend to see it as part of our wider performance efforts in 6.1.x. |
Working on it today!
From: Yanming Zhou ***@***.***>
Sent: Wednesday, January 24, 2024 10:58 PM
To: spring-projects/spring-framework ***@***.***>
Cc: Engebretson, John ***@***.***>; Mention ***@***.***>
Subject: Re: [spring-projects/spring-framework] Improve Spring AOP performance for methods without specific advice (Issue #32104)
@jengebr<https://github.com/jengebr> Could you confirm the improvement works as expected?
—
Reply to this email directly, view it on GitHub<#32104 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/ARRS4IKFFW7TODPHE6O2GKTYQHQ5NAVCNFSM6AAAAABCI46XG6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSMBZGM2TMMBQGU>.
You are receiving this because you were mentioned.Message ID: ***@***.***>
|
I implemented the same change on 5.3.31, ran non-production benchmarks, and confirm the following:
There is also an unexpected yet consistent reduction in application startup time. About 1.5%. |
Very nice to hear, thanks for the immediate feedback! I suppose the startup time reduction comes from the initial introspection of all those methods (which used to populate the method cache) where we only perform that introspection once per class now if there is no method-specific advisor to begin with. |
Out of curiosity, do you have plans to upgrade to Spring Framework 6.x any time soon? Anything holding you back? Also, which JDK generation are you on? There have been quite a lot of performance-related enhancements in 6.1.x in particular. We've also seen significantly better performance in JDK 17 and 21. |
I inquired this morning, and the short answer is organizational inertia. Our in-house framework defines the Spring dependency and upgrading that framework creates breakage risk to many, many applications. Based on your comments, I've started a conversation about whether we do one-off upgrades to performance-critical applications, but even that would take a while.
We're on JDK17, running on a mix of Intel and ARM cpus. Thanks for the poke on this! |
Can you confirm the EOL for 5.3 is Dec-31 2024, as listed at https://endoflife.date/spring-framework? Also, what is the next LTS version? |
@jengebr our official support policies are listed on our website: https://spring.io/projects/spring-framework#support (which I believe the endoflife website copies over). We don't ship LTS versions per se, we just tend to support the last minor version in a generation a bit longer to help with the major upgrade. Our next major version is not announced yet. Once you're on a 6.x version, efforts to upgrade to the latest minor should be minimal. |
The internal 5.3.1 equivalent of this change reached production and had the desired effect - the near-elimination of |
@jengebr cool, great to hear! As for 5.3.x, the last 5.3.x release is actually planned for August 2024, along with the last 6.0.x release. With that remaining timeline, I'm not sure adding such a performance improvement to those lines is still feasible, given that there is always a risk for regressions. |
Thank you, that makes sense. We'll focus on the upgrade. :) |
**Affects:**5.3.x
We have a high-volume, latency-sensitive, customer-facing web application built on Spring MVC. Performance profiling shows that
org.springframework.aop.framework.AdvisedSupport.getInterceptorsAndDynamicInterceptionAdvice()
uses 1% of cpu, and is always called byorg.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor
. Load tests show that forcing the use ofCglibAopProxy$DynamicUnadvisedInterceptor
instead reduces latency by 5%. Our application does not require the use of Advice, so the undoubtedly-broken feature is an acceptable tradeoff in our case.Based on code diving and a StackOverflow question, proxied beans always use
DynamicAdvisedInterceptor
even when the application defines no advice. This leaves no supported mechanism for avoidingDynamicAdvicedInterceptor
.This is a valuable performance optimization for applications that can use it, but clearly many cannot. Implementing the optimization behind a per-application configuration switch should capture the wins when available, and cause no harm when not available.
The text was updated successfully, but these errors were encountered: