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

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 проект, в котором основная причина медленной сборки — его размеры.
      Рефакторинг кода — это, конечно, хорошая тема для этого проекта, но такая статья будет совершенно не интересна для аудитории Хабра.
      При этом описанная ситуация не является уникальной, поэтому мой опыт может пригодиться другим.

© Habrahabr.ru