I am working on a spring-boot service which is taking around 56 sec to start.
I would like to know if there is a possibility to reduce the application start-up time by configuring multiple threads for start-up process.
Thanks and regards,
Suraj Jannu
By default, no. Spring Inits all of the beans on startup, to fail-fast, and not let the app be up (but not running). If you still would take the chance of runtime failures due to Init error of some beans later, only when needed, you can use Lazy loading: https://howtodoinjava.com/spring5/core/spring-bean-eager-vs-lazy-init
Related
Spring lists SO as the only place to ask questions on their community page, which is why I ask this rather generic question here. It may not be the best fit for SO, but, according to Spring's community overview page, there's no other adequate place to ask such questions.
I have a spring boot application built on spring cloud gateway (version 2) which also uses an embedded hazelcast cluster. It runs in multiple instances, which communicate via hazelcast. Everything works fine, except under heavy load. If one instance fails, restarting it is no longer possible.
When the instance is restarted while the cluster of instances is under heavy load, it will start creating and wiring beans, up to some point, after which it will not do anything spring-related anymore. Hazelcast-generated messages are visible in the log (with root log level DEBUG), past that point, but nothing generated by spring or the application itself.
In order to restart that one instance that failed, I need to stop the load generation, wait some 10-15 minutes, then restart the failed instance. Then the new/restarted instance starts up rather quickly, with no problems at all.
The load consists of http requests which get proxied to another application, and is of such nature that it generates a lot of read accesses to hazelcast's distributed storage, but very few writes.
My problem: I have no idea how to debug this. Since the http endpoint never becomes available, there's no way I can query metrics or other actuator information.
So my question is: what tools or mechanisms can I employ to debug this problem? I.e. how can I find out exactly how the boot sequence under heavy load of the other instances of the hazelcast cluster differs from the boot sequence when there is no load at all in the cluster? Once I have this information, the problem is narrowed down enough for me to investigate it further on my own.
I didn't find a way to debug the problem, but had an idea of what might cause it, tried it, and it was a fix.
My application was running as a Kubernetes deployment. A few beans inside the application were relying on a usable CP subsystem during their initialization. Spring's bean initialization process is by necessity sequential and blocking, to account for inter-bean dependencies.
I hypothesized that under heavy load, for whatever reason, the initialization of those beans was blocking forever. As a first experiment, I made that initialization code async, so that Spring can finish bean wiring, even if, until that async part finished too, the instance was unable to perform usable work, to see if that was the problem, at least.
To my surprise, that fully fixed the problem. This way, Spring finished bean wiring, the HZ-dependant initialization also finished rather quickly, when executed async, even under high load, and the instance became usable soon after being started.
I didn't have the time to dig deeper to find out what the precise failure mechanism was. What I believe might have been the problem is the interaction between HZ and K8s. K8s-based discovery works using a K8S service. A pod/instance isn't added to the service until it becomes healthy. If a bean inside the application prevents initialization, the instance is never added to the service. As such, discovery never finds the new/restarted instance. I don't know what effect this might have on the HZ cluster's inner workings.
I am running Spring boot application with 2 instances.Here i am going to use scheduler to run my application.For avoiding Scheduler not to run in two instances at same time using schlock .but schlock i have to mention for atleastfor or atmostfor .My problem is i dont want to release the lock based on time because since using batch application with rest call dont know when my scheduler get complete process.Kindly provide any suggestion running my scheduler with one instance at time without time constraint.
ShedLock requires lockAtMostFor for cases when the node dies. You can try KeepAliveLockProvider to automatically extend the lock.
I have a monolithic Spring MVC application consists of about 1,000 beans and it will cost about two minutes to startup.
Now I am researching to find out why it startup too slow. I added a BeanFactoryPostProcessor to record the launch time and use ApplicationListener to listen to the ContextRefreshedEvent and record the time that the ApplicationContext has refreshed. Then the result shows that the application takes about 80 seconds to finish initializing the ApplicationContext.
After reviewing the code, I found there are two many circular dependencies in the code.
I am wondering if it is the circular dependencies that cause the ApplicationContext start too slow? What I can do to speed up the startup time?
The approaches I have tried include:
Check the #PostConstruct to find out if it is asynchronous.
Adjust the -Xmx and -Xms options.
Add lazy-init to the beans.
Seems not working.
Any help will be appreciated.
I assume you are using Spring Boot and then you are implicitly using the annotation component scan. So, Spring will scan each class in order to create Bean. A possible solution could be use #ComponentScan("packageToScan") instead of #ComponentScan.
However, I do not know your goal but think if you really need to speed up the startup.
We have 40+ spring boot apps and when we try to start all of them together parallel, it takes about 9 to 10 minutes. And we notice that CPU usage is always 100% throughout this entire duration.
After all apps come up successfully and registered with Eureka, CPU usage is back to normal (on average ~30-40% CPU usage after startup).
It seems each spring boot app is taking at least about 15-20 seconds to startup, which we are not happy with since application is relatively small to start with.
We also disabled spring boot auto-configuration so to make sure only required "matching" classes are loaded at start up by spring boot. And we only gained about 1 or 2 seconds at startup after this change.
We seem to have enough system resources with 8 core CPUs and 32 gb of memory on this VM.
Spring boot version is 1.3.6.RELEASE.
Is it something to do with Spring boot? Because even when we startup single spring boot app it spikes CPU to 70-80% usage. Your help is very much appreciated!
This is more of how many beans and Auto Configurations that get executed while the application being started.
For even a simple web application along with JPA, there is a webcontainer and its thread pools, DataSources initializations and many more supporting beans and auto configurations that need to get initialized. These are some serious resource taking actions and they all are rushed at the start of the application to get application booted as soon as possible.
Given that you are starting 40+ apps like these simultaneously, the server will have to pay its toll.
There are ways you can improve the application boot time.
Remove unnecessary modules and bean definitions from your application. Most common mistake a developer makes is to include a spring-boot-starter-web when the application doesn't even need a web environment. Same goes for other starter modules.
Make use of Conditional Bean definitions with the use of #ConditionalOnMissingBean #ConditionalOnProperty #ConditionalOnClass #ConditionalOnBean #ConditionalOnMissingClass #ConditionalOnExpression. This might backfire if you make spring to check for beans with lots of conditions.
Make use of spring profiles. If you don't want a specific set of beans not to be part of that running instance you can group them into a profile and enable them or disable them
Configure initial number of threads a web container can have. Same goes for Datasources. Initiate your pool with only required number of active threads.
Using lazy-initialization for beans by annotating your classes or beans with #Lazy. This annotation can be per bean or against an entire #Configuration.
If that doesn't satisfy your needs, you can always throttle the CPU usage per process with commands like nice or cputools.
Here is an article around cputools.
I have a Spring-WS web service that has three issues:
Slow startup time
Slow generation of the dynamic WSDL
Heavy usage of PermGen (app has to be 1.6 compatible)
Currently, the spring-ws-servlet.xml file has several <context:component-scan> elements for autowired dependencies. Two of these scan nearly everything in two external libraries containing Hibernate DAO and Entity classes. Similarly, the Hibernate session factory bean scans a large number of entities from these two libraries.
So, my questions:
Obviously, we would see at least some performance improvement by limiting the scope of the <context:component-scan> elements. But really, would it be that much?
Similarly, would I see improvements by limiting the scope of what Entities are scanned by the session factory?
Making these changes will NOT be a quick process (alter code, test, etc). Therefore, if anyone can add their wisdom, I would greatly appreciate it.
Actually I am developing a spring ws application on Google Cloud and I also have the same problem with slow start up time. The biggest difference that I have notice was when I have moved to aspectj compile time weaving using aspectj-maven-plugin. If you haven't done this yet try this one. The result may be vary depends on your code and deployment environment. On the cloud every file operation is much slower so this may be a reason why this work for me so well.