Startup Performance of Tomcat in Docker

Tomcat startup time is reduced by ~30% by enabling the Shared Class Cache (SCC) in the Docker images.

In my earlier blog , I measured the Performance of Tomcat with Tradelite7 Application without using any docker images and we saw the boost of Startup time with default Shared Cache in OpenJ9. In this article, let’s do some experiments using docker images of Tomcat and how the Shared Class Cache affects the Startup Performance.

As default SCC with OpenJ9 is disabled when running in Docker, we need to explicitly enable SCC. If we enable SCC in runtime, the caching classes and AoT doesn’t persist in docker when it stops. So, one way to get the SCC improvements is by populating SCC during build time.

In this article, I will show how to create an SCC during build and compare the Performance with “No SCC” and “explicit SCC” for Tomcat with OpenJ9.

To start with, I picked the Dockerfile of Tomcat 9 for OpenJ9 from Tomcat Docker library and used it to build the default Tomcat docker images which has “No SCC”.

Now, we have to create a docker image which uses SCC with OpenJ9.
For that, following modifications are done in Docker file

Fig: SCC options
  1. Add JAVA_OPTS which has SharedClassCache related options. -Xshareclasses:name=tomcat_scc,cacheDir=/tmp,enableBCI -Xscmx20M
  1. Do a cold Tomcat Startup run as part of build itself. This helps in creating the SCC required.
  2. Now, change the JAVA_OPTS to make -Xshareclasses flag readonly. , to avoid any AOT that happens at the start of container as it doesn’t give any benefit to the container.

    Below are the lines I added in Dockerfile for above instructions. (just before the EXPOSE 8080 command)
# set variables to create shared class cache
ENV JAVA_SCC_OPTS "-Xshareclasses:name=tomcat_scc,cacheDir=/tmp,enableBCI -Xscmx20M"
ENV JAVA_OLD_OPTS ${JAVA_OPTS}
ENV JAVA_OPTS "${JAVA_SCC_OPTS} ${JAVA_OPTS}"

# Start the tomcat server to create shared class cache
RUN catalina.sh run > /dev/null & sleep 20

# revert JAVA_OPTS to use shared class cache with readonly flag.
ENV JAVA_SCC_OPTS "-Xshareclasses:name=tomcat_scc,cacheDir=/tmp,readonly"
ENV JAVA_OPTS "${JAVA_SCC_OPTS} ${JAVA_OLD_OPTS}"


With the above changes in Dockerfile, we can build an image which uses SCC with OpenJ9. I also created an another image which runs the tomcat Server for 10 times (instead of one time as mentioned in above snippet) to populate the SCC – only to check if that can improve more Startup time.

To calculate the Startup time and Footprint, below methods are used:

  • For Startup time: Need to mount the logs directory of the container into your server and Use the log (catalina.out) generated by the server and look for INFO [main] org.apache.catalina.startup.Catalina.start Server startup in **** milliseconds.
  • For Footprint: I initially used docker stats to collect the Memory_Usage of a container. Because docker stats doesn’t add up Cache memory, the docker with SCC showed lesser memory_usage (which is not we are looking for!)
    So, I had to measure it by summing up RSS of a process and Huge pages used (if enabled). RSS of a process is calculated using “ps -p <pid> -o rss”. Huge Pages used is the difference of the value from “/proc/meminfo” before and after the tomcat Startup.

The command below is used to start the docker container:

docker run -v $PWD/logs:/usr/local/tomcat/logs --cpuset-cpus="0-3" --cpuset-mems="0" -d <image>

Below are the results of Startup and Footprint from my experiments:

Above graphs Y-axis uses normalized data since it’s the relative picture that matters.

From the graph data above, OpenJ9-ExplicitSCC(with 10 warm-ups during build) didn’t help much in reducing the Startup time as OpenJ9-ExplicitSCC (which does a single run during build) also gave similar results.

Size of docker images (on disk) with tomcat using ExplicitSCC and the original one are:

Docker Image                    SIZE
tomcat_explicitscc:latest       366MB
tomcat:latest                   345MB

All Above experiments are done on a machine with following config

  • CPU Type: Intel(R) Xeon(R) Gold 6126 CPU @ 2.60GHz
  • 24 physical, 48 logical processors.
  • Pinned 4 processors to the server during the run. (used numactl — physcpubind=0–3 — membind=0)

Summary:

  • From the data we got, we can confirm that OpenJ9 with SCC has an out-of-box ~30% reduced Startup time with only 2% increase in Footprint against no SCC.
  • Because of this reduced Startup time, the Tomcat community should perhaps consider adding a step to create an SCC by doing a single start of Tomcat Server during build into their OpenJ9 based docker images.

Leave a Reply