I'm trying to migrate web applications from JBoss to Spring Boot, but have some unexplained issue with VERY slow startup time.
Even simple application from Spring Boot guides - "Handling Form Submission" (packaged as a fat JAR, using Java 1.8) starts on some computers in 3 sec, but on others in 30 sec. and this is gets worse for bigger web apps (WAR-packaged with JSF, Hibernate, etc) - startup time is 13 sec vs 1500 sec (115 times more!).
Similar apps starts under JBoss or Liberty app servers starts fast everywhere.
Not sure if this is security settings, network, firewall or anti-virus tools.
Looking at the log file, it seems like application spends a lot of time on scanning JARs for TLD files and "reflection" scanning.
Strange, but this is not the issue for apps running in JBoss or Liberty - not sure if same scanning happens there.
As far as I understand, this is done per Servlet specs, but is there any way to skip scanning some JARs?
Where to add catalina.properties file in Spring Boot app, packaged as WAR, as suggested by the message?
Here are examples of log messages:
org.apache.jasper.servlet.TldScanner : No TLD files were found in [jar:file:/C:/Development/workspace-Cloud/PrimeFacesDemoSBwar/target/primefacesdemoSB.war!/WEB-INF/lib/primefaces-5.3.jar]. Consider adding the JAR to the tomcat.util.scan.StandardJarScanFilter.jarsToSkip property in CATALINA_BASE/conf/catalina.properties file.
...
org.reflections.Reflections : Reflections took 79406 ms to scan 7 urls, producing 972 keys and 4573 values
Related
I'm actually working in a huge project providing a server and client spring application. The client - for runtime concerns - is using a xml configuration of its beans but the server does not, leading to an immense start up time (at least 20 minutes) due to the classpath scanning. Which is ok for deployment in its production environment, but is a huge overhead for all the developers waiting for the server to start up may be several times per day.
My Question:
Is there any "easy" way to switch from classpath scanning to a static configuration?
I'm thinking of some kind of xml generation for instance. To me, it should be possible to generate a static configuration file the same way the configuration is done via classpath scanning at start up. Are there any concerns I don't know preventing something like that? Does there exist any kind of generator like that?
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.
Latest project I used Spring boot, and prepare to deploy to production environment, I want to know which way to run application have better performance or have the same performance?
generate a war package and put it in a stand-alone tomcat
generate a jar package and use embedded tomcat
In addition, when publish to production environment if should to remove devtools dependency.
This is a broad question. The answer is it depends on your requirements.
Personally, I prefer standalone applications with Spring Boot today. One app, one JVM. It gives you more flexibility and reliability in regard to deployments and runtime behaviour. Spring Boot 1.3.0.RELEASE comes with init scripts which allows you to run your Spring Boot application as a daemon on a Linux server. For instance, you can integrate rpm-maven-plugin into your build pipeline in order to package and publish your application as a RPM for deployment or you can dockerize your application easily.
With a classic deployment into a servlet container like Tomcat you will be facing various memory leaks after redeployment for example with logging frameworks, badly managed thread local objects, JDBC drivers and a lot more.
Either you spend time to fix all of those memory leaks inside your application and frameworks you use or just restart servlet container after a deployment. Running your application as a standalone version, you don't care about those memory leaks because you are forced to restart in order to bring you new version up.
In the past, several webapps ran inside one servlet container. This could lead to performance degradation for all webapps because every webapp has its own memory, cpu and GC characteristics which may interfere with each other. Further more, resources like thread pools were shared among all webapps.
In fact, a standalone application is not save from performance degradation due to high load on the server but it does not interfere with others in respect to memory utilization or GC. Keep in mind that performance or GC tuning is much more simpler if you can focus on the characteristics of just one application. It gets complicated as soon as you'll need to find common denominator for several webapps in one servlet container.
In the end, your decision may depend on your work environment. If you are building an application in a corporation where software is running and maintained by operations, it is more likely that you are forced to build a war. If you have the freedom to choose your deployment target, then I recommend a standalone application.
In order to remove devtools from a production build
you can use set the excludeDevtools build property to completely
remove the JAR. The property is supported with both the Maven and
Gradle plugins.
See Spring Boot documentation.
I have a simple JSP/Servlet maven application which allows a user to upload an archive file. The application will then unzip the archive which contains XML files, and parse them using basic SAX parsing. It will generate an in-memory representation of these files, and write them to a Neo4J Graph Database, currently in embedded mode.
During development, I used a GlassFish v3 but with production in sight, the request has been made to move from Glassfish to Tomcat and so I did. Apart from a few small issues with Tomcat forcing me to add JSF dependencies despite the fact that I'm not using any JSF, there is one big issue I have with Tomcat atm.
The largest testfile I have takes about 8 seconds to upload and parse on glassfish v3. After that, it takes about 2 seconds less, due to the fact that I don't clean up the uploaded file (yet).
The same file on Tomcat7 takes about 90 seconds to upload and parse the first time. The other times it takes about 20 seconds less, presumably because of the same reason.
In any case, there's a difference in performance of factor 10. I'm a little bit surprised, since I thought that using Tomcat would actually increase the speed due to it being more lightweight than Glassfish, since I'm not really using the advanced functionalities provided by Glassfish.
Has anyone encountered a similar issue, and what did you do to resolve this? Is this even resolvable, or is it due to the way that Tomcat works...
EDIT: The difference appears to be in the code section that is responsible for writing the in-memory representation of the files to the actual database... No idea why though...
I could not find a comparison of Tomcat with Glassfish but yes, the new Glassfish versions are very light weight and have very good performance. I have experienced the same. I guess running an application server instead of a Tomcat is no more huge administration and hardware waste (and you can use light weight EJB 3 and 3.1 if you like). Glassfish installations can be very small in size if you only select the necessary modules.
Check this page. It compares Jboss, Glassfish and Resin
http://hwellmann.blogspot.com/2011/06/java-ee-6-server-comparison.html
And this one compares Glassfish 3.1 and Jboss 6 & 7.
http://hwellmann.blogspot.com/2011/10/jboss-as-7-catching-up-with-java-ee-6.html
Using Tomcat 7, Jeresy 1.12.
Time for launch Tomcat without Jersey is 4 seconds.
When I add the jars of Jersey to tomcat/lib directory, the time for launch goes for 50 seconds. It doesn't matter which servlets I use - even if web.xml is empty (no servlets) it takes that time.
The jar that cause the problem is jersey-servlet-1.12. When I remove it from lib directory, launch time goes normal again. I suspect that the services defined in that jar (\META-INF\services\*) cause the trouble but couldn't find the exact cause...
BTW: metadata-complete="true" didn't solve the problem.
Edit: Problem was confirmed by Jersey team (issue JERSEY-1317). A workaround to this problem is to remove META-INF/services/javax.servlet.ServletContainerInitializer file from jersey-servlet.jar. This will disable some of Servlet3 functionality.
You can also add the jar to tomcat.util.scan.DefaultJarScanner.jarsToSkip list at catalina.properties
This way you can take a newer version of the jar and you don't need to keep in mind that you should edit it.
See http://tomcat.10.x6.nabble.com/tomcat-7-0-29-startup-time-td4984446.html