You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by bu...@apache.org on 2019/04/27 21:09:30 UTC

[Bug 63389] New: Enable Servlet Warmup for Containerization

https://bz.apache.org/bugzilla/show_bug.cgi?id=63389

            Bug ID: 63389
           Summary: Enable Servlet Warmup for Containerization
           Product: Tomcat 9
           Version: 9.0.x
          Hardware: PC
                OS: Linux
            Status: NEW
          Severity: enhancement
          Priority: P2
         Component: Catalina
          Assignee: dev@tomcat.apache.org
          Reporter: isapir@apache.org
  Target Milestone: -----

Some servlets have longer initialization time than others.  In
containerizations in general, with Docker being the most popular ATM, it is a
common practice to do a Warm Up during building the container image, so that
instead of running the servlet for the first time when the container is run,
the servlet is initialized while building the container image.

That way, the startup time of the container is much faster as there is no need
to wait for initialization.

Currently, one hack that many use is to launch Tomcat during the container
build process, wait for an arbitrary length of time, e.g. 10s or 20s, and then
shut Tomcat down.

A nice enhancement would be if we could provide a listener which will accept a
servlet name as an argument, and will shut down Tomcat as soon as that servlet
initialization is completed.

A better way would have been to implement this as a ServletContextListener [1],
but unfortunately the misnomered method contextInitialized() is called when the
context initialization starts and not when it ends.


[1]
https://docs.oracle.com/javaee/7/api/javax/servlet/ServletContextListener.html

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 63389] Enable Servlet Warmup for Containerization

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=63389

--- Comment #9 from Mark Thomas <ma...@apache.org> ---
Since this is synchronous, we can use the exit code to signal success or
failure.

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 63389] Enable Servlet Warmup for Containerization

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=63389

--- Comment #7 from Mark Thomas <ma...@apache.org> ---
Thinking about this some more, I think the best way to handle this is with a
new "warmup" command. Implemented in a similar manner to configtest it would
call server.start() followed by server.stop().

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 63389] Enable Servlet Warmup for Containerization

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=63389

--- Comment #10 from Eugène Adell <eu...@gmail.com> ---
(In reply to Igal Sapir from comment #0)
> Currently, one hack that many use is to launch Tomcat during the container
> build process, wait for an arbitrary length of time, e.g. 10s or 20s, and
> then shut Tomcat down.

From your question and some comments, if the problem is with the "arbitrary
length of time", I suggest to rely on JMX particularly on the Connector
stateName value. It is changing from INITIALIZED to STARTED once Tomcat has
finished deploying. If you can bring ANT within your docker, the effort is not
that huge, you just need 2 targets, one for monitoring the Connector state, and
one for stopping Tomcat.

This is the result that I get with a servlet called at the startup and that
sleeps 60 during its initialization :

catalina.out
09-Jul-2019 22:10:55.804 INFO [localhost-startStop-5]
org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web
application directory
[/home/eadell/tests/apache-tomcat-8.5.15/webapps/host-manager] has finished in
[27] ms
09-Jul-2019 22:10:55.879 FINE [localhost-startStop-4]
org.apache.catalina.authenticator.AuthenticatorBase.startInternal No
SingleSignOn Valve is present
09-Jul-2019 22:10:56.055 INFO [localhost-startStop-4]
org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web
application directory
[/home/eadell/tests/apache-tomcat-8.5.15/webapps/examples] has finished in
[793] ms
09-Jul-2019 22:11:55.779 INFO [localhost-startStop-3]
org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web
application directory
[/home/eadell/tests/apache-tomcat-8.5.15/webapps/slowstart] has finished in
[60,518] ms
09-Jul-2019 22:11:55.790 INFO [main] org.apache.coyote.AbstractProtocol.start
Starting ProtocolHandler ["http-nio-8280"]
09-Jul-2019 22:11:55.811 INFO [main] org.apache.coyote.AbstractProtocol.start
Starting ProtocolHandler ["http-nio-8281"]
09-Jul-2019 22:11:55.815 INFO [main] org.apache.catalina.startup.Catalina.start
Server startup in 60719 ms
09-Jul-2019 22:11:57.411 INFO [main]
org.apache.catalina.core.StandardServer.await A valid shutdown command was
received via the shutdown port. Stopping the Server instance.
09-Jul-2019 22:11:57.412 INFO [main] org.apache.coyote.AbstractProtocol.pause
Pausing ProtocolHandler ["http-nio-8280"]
09-Jul-2019 22:11:57.469 INFO [main] org.apache.coyote.AbstractProtocol.pause
Pausing ProtocolHandler ["http-nio-8281"]
09-Jul-2019 22:11:57.521 INFO [main]
org.apache.catalina.core.StandardService.stopInternal Stopping service
[Catalina]
destroying LongInitServlet

shell output
$ time (bin/startup.sh ; ant -f anted-jmx/project.xml buildAndStop)
Using CATALINA_BASE:   /home/eadell/tests/apache-tomcat
Using CATALINA_HOME:   /home/eadell/tests/apache-tomcat
Using CATALINA_TMPDIR: /home/eadell/tests/apache-tomcat/temp
Using JRE_HOME:        /usr/local/java/1.9
Using CLASSPATH:      
/home/eadell/tests/apache-tomcat/bin/bootstrap.jar:/home/eadell/tests/apache-tomcat/bin/tomcat-juli.jar
Tomcat started.
Buildfile: /home/eadell/tests/apache-tomcat-8.5.15/anted-jmx/project.xml

waitMBEAN:
     [echo] Server url alive

shutdown:
     [echo] shutting down ${tomcat.catalina_base}

buildAndStop:

BUILD SUCCESSFUL
Total time: 1 minute 3 seconds

real    1m4.673s
user    0m5.157s
sys     0m0.600s


Here are the ANT targets :

<target name="waitMBEAN">
  <jmxOpen host="${jmx.server.name}" port="${jmx.server.port}"
username="controlRole" password="******" />
  <waitfor maxwait="1200" maxwaitunit="second" timeoutproperty="server.timeout"
>
      <jmxCondition
        operation="=="
        name="Catalina:type=Connector,port=8281"
        attribute="stateName" value="STARTED"
      />
  </waitfor>
  <fail if="server.timeout" message="Server url don't answer inside 1200 sec"
/>
  <echo message="Tomcat finished starting" />
</target>

<target name="shutdown" description="stop tomcat">
    <echo message="shutting down ${tomcat.catalina_base}" />
    <exec executable="/bin/bash">
        <arg line="${catalina.home}/bin/shutdown.sh" />
    </exec>
</target>

<target name="buildAndStop" depends="waitMBEAN,shutdown" />

If required you could also add targets to call servlets, and stop once you have
finished these calls.

Of course, remember to use a random JMX password then you would not compromise
all of your Tomcats if something bad happened.

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 63389] Enable Servlet Warmup for Containerization

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=63389

Brooke T. Hedrick <br...@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|brooke.t.hedrick@gmail.com  |

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 63389] Enable Servlet Warmup for Containerization

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=63389

Brooke T. Hedrick <br...@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |brooke.t.hedrick@gmail.com

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 63389] Enable Servlet Warmup for Containerization

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=63389

--- Comment #6 from Igal Sapir <is...@apache.org> ---
(In reply to Christopher Schultz from comment #5)
> (In reply to Igal Sapir from comment #4)
> > (In reply to Christopher Schultz from comment #3)
> > > I'm definitely missing something, here. Launching Tomcat and then shutting
> > > it down saves zero time on the next launch except maybe to create a
> > > directory or two and unpack any WAR archives being deployed.
> > 
> > This is not for creating the Tomcat directory structure, but all of the
> > initialization of the servlet itself.
> 
> So if the servlet does something like downloading a bunch of files or
> whatever? I mean, the JVM stops, so reading db info into a cache or
> something doesn't help. Just making sure that this has nothing to do with
> Tomcat itself, which won't benefit at all.

Right.  Not Tomcat itself.

> 
> > > If you want to warm the application, you'll want to pre-compile all the JSPs
> > > either using jspc or by just spamming the application with web requests.
> > > 
> > > So what exactly is the point, here?
> > 
> > This is not a JSP per-se, even though it follows the JSP interface.  In this
> > case it is the Lucee Application Server that implements a CFML engine.
> 
> Gotcha. I'm curious what the Lucee engine does on startup that happens ONE
> TIME instead of each time the application is launched.

In addition to Extensions (more below), some of the initial setup is to create
directories and files for the application during initialization.  That only
happens once so the first time Lucee is launched takes much longer than
subsequent launches.  

This is exactly the issue that this enhancement proposes to fix.  Do the first
launch during the `docker build` process so that `docker run` will start much
faster.

> 
> > > I can see use-cases for building something like this (some people want to
> > > know when Tomcat is "really started"), but for triggering a shutdown to
> > > "warm" an app server? I don't get it.
> > 
> > The Application Server can take a while on first run because according to
> > configuration settings it might download extensions and install them, etc. 
> > Without downloading extensions it takes about 3.5s to launch on my latptop. 
> > With extensions it can take up to 60s.
> 
> So these are extensions for Lucee?

Yes.  Lucee has many different extensions, e.g. database drivers, cache
providers, PDF generators, Chart generators, etc.  Some extensions are provided
by the Lucee project [1] while others provided by 3rd party vendors. 
Developers can configure which extensions their application requires to control
the image size.

> 
> > In monolith deployments that might have been acceptable, but in Docker or
> > server-less deployments it is not.
> 
> I have to admit that I find "serverless servlets" an amusing construct.

;-)

[1] https://github.com/search?p=3&q=org%3Alucee+ext&type=Repositories

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 63389] Enable Servlet Warmup for Containerization

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=63389

--- Comment #5 from Christopher Schultz <ch...@christopherschultz.net> ---
(In reply to Igal Sapir from comment #4)
> (In reply to Christopher Schultz from comment #3)
> > I'm definitely missing something, here. Launching Tomcat and then shutting
> > it down saves zero time on the next launch except maybe to create a
> > directory or two and unpack any WAR archives being deployed.
> 
> This is not for creating the Tomcat directory structure, but all of the
> initialization of the servlet itself.

So if the servlet does something like downloading a bunch of files or whatever?
I mean, the JVM stops, so reading db info into a cache or something doesn't
help. Just making sure that this has nothing to do with Tomcat itself, which
won't benefit at all.

> > If you want to warm the application, you'll want to pre-compile all the JSPs
> > either using jspc or by just spamming the application with web requests.
> > 
> > So what exactly is the point, here?
> 
> This is not a JSP per-se, even though it follows the JSP interface.  In this
> case it is the Lucee Application Server that implements a CFML engine.

Gotcha. I'm curious what the Lucee engine does on startup that happens ONE TIME
instead of each time the application is launched.

> > I can see use-cases for building something like this (some people want to
> > know when Tomcat is "really started"), but for triggering a shutdown to
> > "warm" an app server? I don't get it.
> 
> The Application Server can take a while on first run because according to
> configuration settings it might download extensions and install them, etc. 
> Without downloading extensions it takes about 3.5s to launch on my latptop. 
> With extensions it can take up to 60s.

So these are extensions for Lucee?

> In monolith deployments that might have been acceptable, but in Docker or
> server-less deployments it is not.

I have to admit that I find "serverless servlets" an amusing construct.

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 63389] Enable Servlet Warmup for Containerization

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=63389

--- Comment #2 from Igal Sapir <is...@apache.org> ---
(In reply to Mark Thomas from comment #1)
> Start and stop are synchronous. Calling start() then stop() should be
> sufficient. Doing that with the current startup scripts is a little trickier
> because you need to wait for the shutdown port to open.
> 
> Something like:
> ./catalina.sh start && sleep 1 && ./catalina.sh stop
> 
> should work however long the web application takes to start up.

On my laptop the servlet takes about 3 seconds to initialize (though on some
cloud deployments I have seen it take as much as 15s).

From testing the above compounded command it seems to me that the shutdown port
only opens after the servlet initialization, so waiting 1 or 2s does not work
[1].

If we could start listening the shutdown port at the beginning of the process,
and then it can be a blocking operation until start completes, then that would
be a great a solution.

Thoughts?

[1] /workspace/src/tomcat-master$ output/build/bin/catalina.sh start && sleep 2
&& output/build/bin/catalina.sh stop
Using CATALINA_BASE:   /workspace/test/catalina-base
Using CATALINA_HOME:   /workspace/src/tomcat-master/output/build
Using CATALINA_TMPDIR: /workspace/test/catalina-base/temp
Using JRE_HOME:        /opt/java/jdk1.8.0_202
Using CLASSPATH:      
/workspace/src/tomcat-master/output/build/bin/bootstrap.jar:/workspace/src/tomcat-master/output/build/bin/tomcat-juli.jar
Tomcat started.
Using CATALINA_BASE:   /workspace/test/catalina-base
Using CATALINA_HOME:   /workspace/src/tomcat-master/output/build
Using CATALINA_TMPDIR: /workspace/test/catalina-base/temp
Using JRE_HOME:        /opt/java/jdk1.8.0_202
Using CLASSPATH:      
/workspace/src/tomcat-master/output/build/bin/bootstrap.jar:/workspace/src/tomcat-master/output/build/bin/tomcat-juli.jar
Apr 29, 2019 10:58:34 AM org.apache.catalina.startup.Catalina stopServer
SEVERE: Could not contact [localhost:8005] (base port [8005] and offset [0]).
Tomcat may not be running.
Apr 29, 2019 10:58:34 AM org.apache.catalina.startup.Catalina stopServer
SEVERE: Error stopping Catalina
java.net.ConnectException: Connection refused (Connection refused)
        at java.net.PlainSocketImpl.socketConnect(Native Method)
        at
java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
        at
java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
        at
java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
        at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
        at java.net.Socket.connect(Socket.java:589)
        at java.net.Socket.connect(Socket.java:538)
        at java.net.Socket.<init>(Socket.java:434)
        at java.net.Socket.<init>(Socket.java:211)
        at org.apache.catalina.startup.Catalina.stopServer(Catalina.java:513)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.apache.catalina.startup.Bootstrap.stopServer(Bootstrap.java:390)
        at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:480)

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 63389] Enable Servlet Warmup for Containerization

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=63389

--- Comment #1 from Mark Thomas <ma...@apache.org> ---
Start and stop are synchronous. Calling start() then stop() should be
sufficient. Doing that with the current startup scripts is a little trickier
because you need to wait for the shutdown port to open.

Something like:
./catalina.sh start && sleep 1 && ./catalina.sh stop

should work however long the web application takes to start up.

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 63389] Enable Servlet Warmup for Containerization

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=63389

--- Comment #8 from Christopher Schultz <ch...@christopherschultz.net> ---
I have a slight objection to the term "warmup" being used, here.

Can we call it something else?

Nothing brilliant comes to mind.

"updown"?
"startstop"?
"launchtest"?

Perhaps such a special launch command could provide some output such as "OK" if
everything is okay, or some kind of error words/codes which describe what
happened. For example, if one of the connectors failed to start properly, we
could report that failure. Perhaps the same for any configured auto-deploy
application that failed to start cleanly.

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 63389] Enable Servlet Warmup for Containerization

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=63389

--- Comment #4 from Igal Sapir <is...@apache.org> ---
(In reply to Christopher Schultz from comment #3)
> I'm definitely missing something, here. Launching Tomcat and then shutting
> it down saves zero time on the next launch except maybe to create a
> directory or two and unpack any WAR archives being deployed.

This is not for creating the Tomcat directory structure, but all of the
initialization of the servlet itself.

> If you want to warm the application, you'll want to pre-compile all the JSPs
> either using jspc or by just spamming the application with web requests.
> 
> So what exactly is the point, here?

This is not a JSP per-se, even though it follows the JSP interface.  In this
case it is the Lucee Application Server that implements a CFML engine.

> I can see use-cases for building something like this (some people want to
> know when Tomcat is "really started"), but for triggering a shutdown to
> "warm" an app server? I don't get it.

The Application Server can take a while on first run because according to
configuration settings it might download extensions and install them, etc. 
Without downloading extensions it takes about 3.5s to launch on my latptop. 
With extensions it can take up to 60s.

In monolith deployments that might have been acceptable, but in Docker or
server-less deployments it is not.

You can find more information in the Lucee ticket system [1], where I actually
resolved the issue for Lucee but it feels like a hack and would be much better
if resolved on the Tomcat level as 1) it will be cleaner, and 2) it will help
other projects who might need this feature.


[1] https://luceeserver.atlassian.net/browse/LDEV-1196

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 63389] Enable Servlet Warmup for Containerization

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=63389

--- Comment #3 from Christopher Schultz <ch...@christopherschultz.net> ---
I'm definitely missing something, here. Launching Tomcat and then shutting it
down saves zero time on the next launch except maybe to create a directory or
two and unpack any WAR archives being deployed.

If you want to warm the application, you'll want to pre-compile all the JSPs
either using jspc or by just spamming the application with web requests.

So what exactly is the point, here?

I can see use-cases for building something like this (some people want to know
when Tomcat is "really started"), but for triggering a shutdown to "warm" an
app server? I don't get it.

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org