Pull to refresh

Как ускорить сборку с Maven

Reading time 3 min
Views 30K
Maven
Что делать, если сборка (build) с Maven проходит слишком медленно? Ведь когда сборка длится слишком долго, любой, даже самый терпеливый разработчик, может заскучать и отвлечься.

Для быстрого поиска в Google или для закладок, сразу предлагаю итоговое решение:
mvn package -am -o -Dmaven.test.skip -T 1C

— для сборки проекта без тестов.

Эта история началась с того, что я выкачал довольно большой проект на Java из нашего корпоративного репозитория. Думаю, что многие, как и я, сразу собрали бы его командой:
mvn clean package

, ну а многие командой:
mvn clean install

Мой проект собрался за 25 минут, и каждый раз собирался так же долго, как и в первый раз.

package вместо install


Согласно жизненному циклу сборки проекта после фазы package, на которой мы получаем полноценный jar-файл, есть фаза verify, а затем install. Часто необходимо получить именно jar-файл, который нет необходимости помещать в локальный репозиторий, поэтому в данной ситуации я остановился на package и сэкономил немного времени.

Параллельная сборка


При обычном запуске Maven не использует все возможности современных процессоров по распараллеливанию вычислений на разных ядрах, собирая модули один за другим. К счастью, можно воспользоваться параметром -T, указав Maven, что необходимо построить граф зависимостей и собирать модули параллельно.
Параметром можно воспользоваться разными способами:
mvn -T 4 package

или
mvn -T 1C package

В первом случае вы указываете число потоков для использования Maven, а во втором — что необходимо использовать один поток на каждое ядро CPU.
Второй способ задания параметра, привязанный к количеству ядер, я и собираюсь использовать в своей итоговой команде.
Поэкспериментировав с количеством потоков на ядро, попробовав следующие варианты:
mvn -T 1C package
mvn -T 1.5C package
mvn -T 2C package

— я не получил какого-то заметного прироста в случае с более чем 1 потоком на ядро на собираемом проекте на процессоре Core i7.
Замечу ещё, что параллельная сборка — это экспериментальная функция Maven 3. При сборке могут возникнуть проблемы при использовании плагинов, не являющихся @threadSafe. В частности, это плагины:
  • Surefire с параметром forkMode=never, surefire [2.6,) предупреждает (assert) об этом.
  • maven-modello-plugin, исправлено с версии 1.4,
  • Все клиенты maven-archiver (EAR, EJB, JAR, WAR etc), исправлено в последних версиях

и библиотеки:
  • plexus-utils 2.0.5
  • maven-archiver 2.4.1
  • plexus-archiver 1.0
  • plexus-io 1.0


Инкрементальная сборка


Как мы обсуждали выше, проект чаще всего собирается командой:
mvn clean package

Команда clean используется для очистки проекта, но так ли это нужно каждый раз при сборке? Нет, обычно мы хотим инкрементального обновления проекта, и Maven на это способен при помощи команды:
mvn package -am

Maven собирает модуль и обновляет те модули, от которых зависит данный модуль, в случае если в них что-то поменялось.
Эта опция в разы ускоряет сборку проектов из многих модулей, в которых, как правило, вносятся точечные изменения в 1-2 модуля.

Оффлайновая сборка


Часто бывает так, что артефакты на внешних репозиториях обновляются не так уж и часто, особенно, когда это артефакты определённой версии, или эти артефакты должны поддерживаться вашими усилиями (- Добро пожаловать в новый проект!). Довольно логично в такой ситуации сообщить Maven, что не нужно каждый раз заново скачивать их из репозиториев:
mvn package -o

или
mvn package --offline


Мы для лаконичности остановимся на первом варианте.

Пропуск тестов


Пожалуй, самое спорное предложение по оптимизации скорости сборки я оставил напоследок. Тем, кто полностью разделяет ценности TDD, я просто предлагаю пролистнуть этот абзац и убрать из нашей итоговой команды параметр -Dmaven.test.skip.
Не буду отрицать, тесты, безусловно, нужны, и программист должен понимать ту часть ответственности, которую он берёт на себя, отключая их. Но если вы вдруг столкнулись с новым гигантским проектом, в котором кто-то когда-то написал тесты, и они не работают, то вам и так придётся их для начала отключить.
Что касается опции запуска Maven, я хочу отметить только то, что, как правило, для того, чтобы пропустить тесты пользуются командой:
mvn package -DskipTests

Но при этом можно также пропустить компиляцию тестов, если выполнить команду в следующем виде:
mvn package -Dmaven.test.skip


Подведём итоги


Итак, ещё раз команда, которая получилась у нас для ускорения сборки с Maven:
mvn package -am -o -Dmaven.test.skip -T 1C


Результат, показанный на собираемом мной проекте, радует: сборка вместо 25 минут стала проходить за 30 секунд.
Авторы некоторых других статей по оптимизации скорости сборки с Maven также рекомендуют использовать параметры оптимизации запуска компилятора:
MAVEN_OPTS= -XX:+TieredCompilation -XX:TieredStopAtLevel=1
mvn package

— но, во-первых, я не почувствовал какого-то реального ускорения сборки, по всей видимости, из-за того, что я и так пользовался инкрементальной сборкой и процесс компиляции отнимал в этом случае не так много времени, а во-вторых, встречается достаточное количество упоминаний того, что эти параметры могут вызвать ошибки OutOfMemory и прочие проблемы.

Надеюсь, что в комментариях вы также поделитесь статистикой по ускорению сборки ваших проектов!
Tags:
Hubs:
+23
Comments 40
Comments Comments 40

Articles