Ускоряем процесс сборки с maven

    Наверное многие из Вас работают с Maven. Если так, то полагаю каждый из Вас ежедневно собирает свой проект по несколько раз, особенно если Вы сейчас в активной фазе разработки и изменения затрагивают много модулей. В определенный момент времени проект становится довольно большим и билд с каждым днем начинает выполнятся все дольше и дольше… И вот приходит время, когда пора что-то с этим делать.

    Мигрируйте с Maven 2 на Maven 3

    Вы еще используете maven2? Странно. Одна только миграция на 3-ю версию может значительно ускорить процесс сборки. В моем проекте переход на Maven 3 дал прирост в скорости сборки на 10%. Вероятней всего за счет каких-то фиксов и оптимизаций, что были сделаны в новой версии (так как заявляют разработчики количество кода было существенно уменьшено и сильно отрефакторено). Миграция займет у Вас несколько минут и в большинстве случаев будет безболезненной. Хотя есть шанс, что некоторые конфигурационные файлы все же придется подправить.

    Используем ядра и дополнительные потоки

    В Maven 3 есть замечательная опция:
    mvn -T 4 clean intall
    mvn -T 2C clean install
    

    В первом случае мы явно указываем, что хотим запустить процесс сборки на 4 потока. Во втором случае мы указываем, что на каждое ядро должно быть выделено по 2 потока для процесса сборки. Это одна из новых фич нового мавена — Parallel Builds. Эта фича анализирует граф зависимостей Вашего проекта
    и распихивает модули по разным потокам, сборка которых может быть выполнена параллельно.
    Для моего текущего проекта скорость сборки со вторым параметром (-T 2C) ускорилась на 20%. Правда тут есть один минус. Количество ресурсов, что будет потребляться для билда может значительно вырасти. В моем случае это +30% к потребляемой памяти.
    Хочу сразу обратить внимание — если связанность модулей в Вашем проекте очень низкая — то
    скорость сборки этой опцией можно увеличить на порядок.
    Это, кстати, повод задуматься об Вашей архитектуре проекта. Ведь если билд занимает довольно много времени, то небольшой рефакторинг поможет уменьшить эту цифру. Хотя, конечно, это все очень индивидуально.
    Вообще разработчики заявляют, что прирост в скорости сборки может быть 20-50%.

    Разделяй и властвуй

    Сейчас я скажу банальность, но — если у Вас цельный проект, лучше разбить его на логические модули. Разбиение не должно становится самоцелью. Но чем больше разбиение и меньше зависимости тем быстрее происходит процесс сборки. Распределение тестов по модулям тоже увеличит производительность, да и в принципе это удобно.

    mvnsh

    Maven Shell — по сути, просто активная командная строка maven. Вся фишка в том, что она висит постоянно в памяти, следовательно при каждом новом билде нету необходимости запускать по новой JVM. В дополнение кешируются все конфигурационные файлы и все плагины уже предварительно загружены. Подробней прочитать можно тут и тут.

    Плагины

    Убедитесь, что Вы не используете лишние плагины и не используете дополнительные там, где можно обойтись без них. Мавен — это целая эко-система, поэтому важно понимать, что каждый элемент этой системы влияет на производительность в целом.
    Стоит также упомянуть, что во время билда с параметром "-T" Вы можете обнаружить подобное в логе выполнения:
    [WARNING] *****************************************************************
    [WARNING] * Your build is requesting parallel execution, but project      *
    [WARNING] * contains the following plugin(s) that are not marked as       *
    [WARNING] * @threadSafe to support parallel building.                     *
    [WARNING] * While this /may/ work fine, please look for plugin updates    *
    [WARNING] * and/or request plugins be made thread-safe.                   *
    [WARNING] * If reporting an issue, report it against the plugin in        *
    [WARNING] * question, not against maven-core                              *
    [WARNING] *****************************************************************
    [WARNING] The following plugins are not marked @threadSafe in eridanus-supervoid-module:
    [WARNING] org.codehaus.mojo:jboss-maven-plugin:1.5.0
    

    Поэтому, собственно, желательно использовать последние версии плагинов, потому что они с большой вероятностью могут быть уже thread-safe. Как Вы понимаете — если плагин не thread-safe, то все его задачи, не могут быть распределены между потоками при опции "-T".

    Буду благодарен за любую дополнительную информацию, которая поможет ускорить сборку.

    Similar posts

    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 23

      0
      Может быть чуть больше текста стоит убрать под кат? ;)
        0
        Я убрал, но не работает
        +1
        Очень полезно. Спасибо.
        А запуски юнит тестов оно не делает паралельными?
          0
          Делает, если тесты не зависят друг от друга и разнесены по модулям.
          +1
          Если ничего не помогло, или если вы недовольны Maven-ом (как многие, очень многие), то вот вам радикальное решение — перепишите сборку на Gradle.
          В плане скорости сборки у них есть совершенно убийственная фича — инктрементальная сборка. Идея состоит в том, что каждая задача определяет свои вводы и выводы (например для задачи javac это будут — исходники и бинарники соответственно). Перед запуском задачи Gradle проверяет вводы и выводы и если ни те, ни другие не изменились, задача не будет бежать вообще.

          Ну и кроме того, у них, естественно, есть все, что есть в Maven-е, будь то многопоточное исполнение или исполняемый на фоне демон-процесс для ускорения инициализации.
            0
            Слышал, но не довелось пока попробовать. Кстати, Gradle интегрирован с ТeamCity?
              0
              На том же уровне, что и Maven.
              0
              Какую версию Gradle используете? Мы гоняли 0.9, но из-за ошибок в кэшировании и, как раз, в инкрементарной сборке отказались.
                0
                нуууу, 0.9 это было так давно, что уже и неправда :-)
              0
              Я пробовал собирать один из рабочих проектов 3-й версией мавена, и не получил практически никакого прироста. Сборка в параллель будет хорошо работать только в том случае, если нет «тяжелых» модулей (как правильно указал автор). Если они есть, особого прироста тоже не будет (в моем случае, вместо 9 минут получилось 8). Еще один момент — не все последние версии плагинов в данный момент thread safe.

              Раз уж речь в коментах зашла о TeamCity, то я обратил бы внимание на одну из ключевых возможностей, которые появились в 7-й версии — инкрементальную сборку. В этом случае TC с помощью собственных механизмов определяет модули, которые затронули закоммиченные изменения, и билдит только то, что нужно. Подробнее можно почитать здесь.
                +1
                Статья ни о чем, можно было бы просто привести ссылку на выхлоп mvn --help с выделением следующего куска:

                -T,--threads Thread count, for instance 2.0C where C is core multiplied

                все.

                И кстати, мавен тоже умеет не компилировать неизменившиеся сырцы.
                  0
                  >>И кстати, мавен тоже умеет не компилировать неизменившиеся сырцы.
                  Как?
                    0
                    Просто не делайте clean, и все.
                    0
                    да, был неправ, пример с сорцами дурацкий. javac сам умеет не компилировать не изменившиеся сорцы. А как на счет, например, не перепаковывать jar?
                      0
                      JAR не надо перепаковывать, только если вы вообще ничего не поменяли. Я не уверен в том как эту ситуацию обработает Maven, но зачем вообще такое пытаться собрать?
                        0
                        Ну, Maven-же не знает, поменяли вы или нет. Вы поменяли что-то в каком-то модуле. Запускаете Maven в рутового проекта. Все, кроме javac, который сам знает, что ничего компилировать не нужно, будет бежать заново — генерация сорцов из дескрипторов, которые не поменялись (например), тесты на классы, которые не поменялись, запаковка в jar-ы файлов, которые не поменялись, и так далее.
                          0
                          javac определяет неизменность исходника сравнивая время изменения исходника со временем создания .class Ни что на самом деле не мешает assembly плагину проверить время создания всех файлов участвующих в запаковке и ничего не делать если уже готовый архив новее.

                          Реализовано это или нет, к сожалению, сейчас не могу проверить. На сколько это оправдано в смысле экономии, тоже неоднозначно. Но факт в том что реализуемо и достаточно легко.
                            –2
                            Ну, тот факт, что ничто с технологической точки зрения не мешает Мавену сосать, не значит что он не сосет, увы и ах.
                            Грейдл лишь подтверждает тот факт, что система сборки может быть намого лучше и умнее, чем Мавен.
                              +2
                              То что вам больше нравится другой инструмент вовсе не означает того, что вам дано право оскорбительно отзываться о других инструментах, которые вполне успешно справляются со многими поставленными задачами.

                              2/3 мои проектов собираются Maven и я знаю в нем много достоинств и недостатков, однако при этом я не позволяю себе столь мерзких суждений в отношении других сборщиков, да и вообще инструментов, которые я использую.

                              Если вам что то не нравится, не пользуйтесь этим!
                                0
                                Напрасно вы так негодуете. Я использовал слово «сосет» не для обзывательств, а для описания отсутствия конкретной функциональности.
                                Грейдл, к сожалению, тоже во многом пока сосет, но счет в его пользу.
                    0
                    >>И кстати, мавен тоже умеет не компилировать неизменившиеся сырцы.
                    Как?
                      +1
                      Maven Shell не поможет на больших проектах. Проблема в баге maven compiler plugin, который приводит к утечке памяти в ClassLoader'е. Как результат, спустя несколько запусков mvnsh бодро валится с OutOfMemoryError.

                      Этот неприятный баг сильно нивелирует достоинства mvnsh. Нет особого смысла кешировать библиотеки, если спустя пару-другую сборок придётся перезапускать шелл. Особого выигрыша в скорости не возникает, не говоря уже о том, что сам процесс сборки становится менее предсказуемым и более нервным.

                      Наращивание места под PermGen лишь отсрочит проблему, но не решит её. Падения станут происходить чуть реже, но за счёт занятой памяти. Это не похоже на выгодную сделку…
                        0
                        В моем случае разбиение на модули хорошее, но сильно тормозит сборку maven-war-plugin со своими оверлеями. Собираем каждый модуль в отдельности. Для деплоя используем war, а во время разработки его распакованную версию в target, достаточно было бы, чтобы эта папка обновлялась только инкрементно, war даже перепаковывать не надо. Задумываюсь о доработке плагина :) Есть мысли?

                        Only users with full accounts can post comments. Log in, please.