Search code examples
javaperformancetomcatstartuptomcat8

Tomcat startup performance : How to prevent waiting until all webapps are deployed?


We have 20 wars in our app and I'm facing a problem which I can't solve.

We have two cases of Tomcat deployment:

  1. Copy artifact after Start
    When you have copied your wars when Tomcat has already been started up you are able to call applications that have already been started before all apps are up and running.

  2. Copy artifact before Start When you have copied your wars when Tomcat has not been started up you will not able to call application until all applications are up and running.

Is there any possibility to configure Tomcat to prevent waiting until all wars are deployed for second case ?

Thanks in advance.


Solution

  • The default Tomcat configuration will make the applications deployment look like anarchic, but there is one way to give a more predictable behaviour by starting applications in a defined order. You still must wait for an application to be deployed before it answers to requests, but at least if one of them needs to be loaded first, you can give it the priority it deserves. Interestingly enough, reading the Tomcat startup documentation doesn't give any clue.

    To achieve this, you implement as many Services/Connectors/Engines/Hosts that you have applications. Maybe you will need a reverse-proxy in front if you want all of them to answer on the same port. Each application will be deployed in its own directory instead of the webapps dir. This is what I'm doing :

      <Service name="app1">
        <Connector port="8881" protocol="HTTP/1.1" address="localhost" />
        <Engine name="Engine1" defaultHost="localhost">
          <Host name="localhost"  appBase="app1" unpackWARs="true" autoDeploy="true" >
          </Host>
        </Engine>
      </Service>
    
      <Service name="app2">
        <Connector port="8882" protocol="HTTP/1.1" address="localhost" />
        <Engine name="Engine2" defaultHost="localhost">
          <Host name="localhost"  appBase="app2" unpackWARs="true" autoDeploy="true" >
          </Host>
        </Engine>
      </Service>
    ...
    

    Edit 1 It's not exactly an answer to the second case, but if you want to avoid deployments during the startup, it is possible to use deployOnStartup="false" in the Host configuration, and this will dramatically speed up the startup. This means all the deployments would be done when Tomcat is already up. Here are the before/after results on a default Tomcat 8.5 (CentOS 7, 6 vcpus) :

    18-Mar-2018 11:53:09.932 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 10628 ms
    18-Mar-2018 11:53:56.200 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 49 ms
    

    Edit 2 An old answer suggests, and I agree with it, that non-compressed wars would speed up the deployments. Maybe you win 10%-15% of the startup time with that.

    Edit 3 As for the two edits above, another parameter can help you to make the startup faster : startStopThreads in the Host definition which is defaulted to 1. Adjust it to the number of cpus you have, on my test with 6 vcpus it's turning the startup twice faster with 1000 sample wars to deploy. This point was discussed in the user mailing list, although it doesn't look to be commonly used. A side effect of this parameter is to also make the shutdown faster, but Tomcat doesn't log metrics for that.

    18-Mar-2018 17:02:45.678 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 15947 ms
    18-Mar-2018 17:07:20.890 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 7594 ms
    

    You can mix several ideas I gave, and feel free to give us a feedback on the performances achieved. I'm tagging your question and suggesting edits to give more visibility that could help other users.

    You may also have a look at the official Tomcat FasterStartUp but it's a bit weak.