Ways to make maven build faster

maven build

In this blog post, I will explain how I reduced maven build time for the project at my workplace.

Project

I work on a multi module maven project and project has following structure.

Project is built on following tech stack

  • Spring Boot
  • Maven
  • Junit
  • PostgreSQL
  • Rabbit MQ
  • Docker

Maven Build

Typically we build our project with below command.

mvn clean packageCode language: Bash (bash)

Let’s record the time taken to build the project

Builds12345
Time ( Min )02:4702:2002:2302:2902:22

Avg. Time ( Min )02:30

Maven supports multi thread building. So I ran following command and recorded the build times.

mvn clean package -T 2CCode language: Bash (bash)
Builds12345
Time ( Min )02:1802:1702:1902:2402:25

Avg. Time ( Min )02:18

There is slight decrease in build time but it is not significant.

[INFO] Reactor Summary:
[INFO] parent-project ..................................... SUCCESS [1.559 s]
[INFO] parent-project-client ..................................... SUCCESS [9.242 s]
[INFO] parent-project-common..................................... SUCCESS [9.097 s]
[INFO] parent-project-migration..................................... SUCCESS [1.009 s]
[INFO] parent-project-persistence..................................... SUCCESS [7.933 s]
[INFO] parent-project-war..................................... SUCCESS [02.03 min]
[INFO] parent-project-component-test................................... SUCCESS [4.054 s]
[INFO] parent-project-performance-test................................. SUCCESS [1.073 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
Code language: Bash (bash)

So I analyzed the my project to see which module is taking more time to build.

My project contains significant number of unit test cases so I ran the build by skipping unit test cases with below command.

mvn clean package -DskipTestsCode language: Bash (bash)

[INFO] Reactor Summary:
[INFO] parent-project ..................................... SUCCESS [1.314 s]
[INFO] parent-project-client ..................................... SUCCESS [8.990 s]
[INFO] parent-project-common..................................... SUCCESS [3.769 s]
[INFO] parent-project-migration..................................... SUCCESS [0.143 s]
[INFO] parent-project-persistence..................................... SUCCESS [4.527 s]
[INFO] parent-project-war..................................... SUCCESS [21.293 s]
[INFO] parent-project-component-test................................... SUCCESS [4.504 s]
[INFO] parent-project-performance-test................................. SUCCESS [1.083 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
Code language: Java (java)

Base on build times with unit tests and with out unit tests, we can conclude that unit tests were impacting the build time.

war project was taking more time to build as it had all the unit test cases.

Forking and Parallel Test execution

It is clear from the results that tests are major contributors in build time. So I was looking for ways to speedup the test case execution. Luckily maven-sure-fire plugin supports forking and parallel test execution to speed up the build. we are using same plugin in our projects.

The plugin supports different configurations. You need to mix and match configuration options and values to achieve the optimum execution time. Please visit the documentation page to see all the configuration options available.

For my project following configuration gave the lowest execution time.

<plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.0</version>
                <configuration>
                    <argLine>-Xmx2G -XX:MaxPermSize=1G -XX:-UseSplitVerifier -XX:-TieredCompilation -XX:TieredStopAtLevel=1</argLine>
                    <parallel>methods</parallel>
                    <forkCount>3C</forkCount>
                    <reuseForks>true</reuseForks>
                    <threadCount>20</threadCount>
                </configuration>
            </plugin>
Code language: XL (xl)
Note
To use forking and parallel test execution feature following are minimum requirements.
Junit 4.7+
Surefire plugin 2.16+

After this change I ran the maven build command again

mvn clean packageCode language: Bash (bash)

Clearly we can see that war project is building faster this time.

[INFO] Reactor Summary:
[INFO] parent-project ..................................... SUCCESS [1.947 s]
[INFO] parent-project-client ..................................... SUCCESS [8.431 s]
[INFO] parent-project-common..................................... SUCCESS [4.619 s]
[INFO] parent-project-migration..................................... SUCCESS [0.120 s]
[INFO] parent-project-persistence..................................... SUCCESS [7.892 s]
[INFO] parent-project-war..................................... SUCCESS [  01.16 min]
[INFO] parent-project-component-test................................... SUCCESS [3.316 s]
[INFO] parent-project-performance-test................................. SUCCESS [0.773 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
Code language: Java (java)

Builds12345
Time ( Min )01:4301:3901:3401:3401:39

Avg. Time ( Min )01:37

Since my project is multi module project, I tried to take advantage of Maven Daemon project and see whether it would fasten the build

Maven Daemon

Maven Daemon project aims at providing faster Maven builds using techniques known from Gradle and Takari.

Advantages

  • The JVM for running the actual builds does not need to get started a new for each build.
  • The class loaders holding classes of Maven plugins are cached over multiple builds. The plugin jars are thus read and parsed just once.

Limitations

  • By default, mvn daemon is building your modules in parallel using multiple CPU cores. If your source tree does not support parallel builds, pass -T 1 on the command line to make your build serial.
  • Can not be used in CI/CD pipeline

How to install Maven Daemon

On Windows

Please visit the link for installation instructions on Linux and Mac OS

Now lets run the builds with maven daemon.

mvnd clean package Code language: Bash (bash)

Builds12345
Time ( Min )01:3901:2601:2001:2001:22

Avg. Time ( Min )01:24

I tried using Maven Daemon with multi threading

mvnd clean package –T 2CCode language: Bash (bash)
Builds12345
Time ( Min )01:1501:2001:1801:2101:22

Avg. Time ( Min )01:19

mvnd clean package –T 4CCode language: Bash (bash)

Builds12345
Time ( Min )01:2001:2101:2101:2201:20

Avg. Time ( Min )01:21

I got optimum execution time with mvnd clean package –T 2C command.

Comparing the build times

Build Command Avg. Build Time delta
mvn clean package02:30 NA
mvn clean package -T 2C02:22– 5 %
mvn clean package ( parallel unit tests)01:37– 35%
mvnd clean package ( parallel unit tests)01:24– 44%
mvnd clean package -T 2C ( parallel unit tests)01:19– 47%
mvnd clean package -T 4C ( parallel unit tests)01:21– 46%

I was able to reduce the build time of my project by 47%

References

Similar Posts