Как ускорить сборку с 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 и прочие проблемы.
Надеюсь, что в комментариях вы также поделитесь статистикой по ускорению сборки ваших проектов!
Комментарии (8)
15 июля 2016 в 08:35
0↑
↓
Дайте попробую угадать — у вас нет своего репозитория в вашей сети?
15 июля 2016 в 08:38
0↑
↓
Почти. У нас удалённый офис, репозиторий есть в основном офисе. Но вы утрируете, т.к. оффлайновая сборка решила мою проблему лишь отчасти.15 июля 2016 в 08:45
0↑
↓
Ну может и утрирую, но я такого никогда не наблюдал, имея всегда nexus рядом.
Могу в принципе себе представить проект, собирающийся 25 минут — например весь karaf или camel, может быть. Только смысла собирать его весь не вижу никакого. И делать проект такого размера, не разбитый на модули — тоже.
takari видели? Пробовали?
15 июля 2016 в 09:00
0↑
↓
Проект, который я собирал, по размерам должен быть сопоставим с karaf или camel, и в нём как раз много модулей. Он отчасти есть в opensource, но по NDA я не думаю, что могу публично назвать его.
Насчёт смысла собирать и пересобирать такой большой проект — если вы ещё раз пробежите текст статьи, там как раз и упоминается возможность не собирать постоянно все модули. Надеюсь, кому-то эта возможность пригодится помимо меня, поэтому я и написал об этом.
Про takari — спасибо за наводку!15 июля 2016 в 09:19
0↑
↓
Ну если он попоставимого с karaf размера — тогда да, понять 25 минут можно. Тогда вам скорее всего еще поможет SSD, а вовсе не i7.
Возможность же не собирать каждый раз все — ну это самый очевидный вариант, на самом деле. Иначе зачем вообще модули?
15 июля 2016 в 09:23
0↑
↓
Да, это с SSD-шкой, кстати.
15 июля 2016 в 09:03
0↑
↓
Ну… Тюнить мавен это конечно хорошо, но как на счет понять причины медленной сборки? Помню у нас билд шел 10 мин, при этом поднятие спринговых контекстов в тестах занимало 6 мин.
+ Отрефакторить код и избавиться от лишнего мусора, которого, я уверен, в проекте хватает.
+ Сборку можно вынести на отдельную мощную машину и собирать там.15 июля 2016 в 09:18
0↑
↓
Как я уже писал, изначально это огромный opensource проект, в котором основная причина медленной сборки — его размеры.
Рефакторинг кода — это, конечно, хорошая тема для этого проекта, но такая статья будет совершенно не интересна для аудитории Хабра.
При этом описанная ситуация не является уникальной, поэтому мой опыт может пригодиться другим.