24/02/2013

Optimisation du Build Maven

 Une de mes premières impression à france billet etait le temps du build maven.

Voici l'etat de nos reflexions et exprimentations

Situation actuelle

  • 364 projets
  • 3 artefacts finaux
  • 13 jobs Hudson pour builder, gérer les évolutions du schema de la base et déployer sur plusieurs environnements dont les premiers sont
    • 1 Job Compilation  + Tests Unitaires
    • 1 Job Test IT avec appel à la base de données
    • 1 Job Integration avec serveurs démarrés
  • 33min pour un build complet en local sans les tests
  • 1 intégrateur à plein temps pour gérer l'usine logicielle

 

Done

Bien connaître les options maven

Le réacteur contient le projet courant et l'ensemble de ses modules.

Les options utiles permettant de ne pas builder l'ensemble du réacteur sont:

  • -pl, –projects Une fois placé à la racine des projets, cette option permet de sélectionner les projets à builder
  • -am, –also-make Build également les dependances des projets selectionnés lorsque celles-ci sont dans le reacteur, ce qui permet de builder u produit à jour
  • -amd, –also-make-dependents Build également les projets du réacteurs qui dépendent des projets selectionnés, ce qui permet de propager les modifications
  • -rf, –resume-from Permet de reprendre un build sur un projet donné, après avoir effectué une correction

http://www.sonatype.com/people/2009/10/maven-tips-and-tricks-advanced-reactor-options/

http://blog.aheritier.net/construire-moins-pour-aller-plus-vite/

Régler les paramêtres de JVM

Sur le build, il y a 3 endroits où j'ai pu configurer la taille allouée pour la JVM

  • Build Maven, avec la variable d'environnement MAVEN_OPTS (Maven indique gentiement la mémoire utlisée en fin de build)
  • Compilation Java, avec la configuration maxmem du plugin maven-compiler-plugin
  • Compilation GWT, avec la configuration extraJvmArgs du plugin gwt-maven-plugin

A manier avec précaution, car si le Xms est trop grand, la mémoire est allouée pour rien, s'il est trop petit, l'allocation progressive est plus coûteuese.

Si le Xmx est trop grand, il y a un risque de freezer la machine, et s'il est trop petit, c'est le java.lang.OutOfMemoryError

http://download.oracle.com/javase/6/docs/technotes/tools/windows/java.html

Spécifier le chemin du parent

Préciser un parent permet de faire de l'héritage et d'éviter de la duplication de configuration.

Lorsque l'on précise un parent, toujours ajouter le relativePath. Cela permet d'utiliser la dernière version du pom parent sans avoir à installer ce dernier.

Fixer les versions

Une grande partie de nos projets sont en SNAPSHOT. Nous ne passons pas par l'étape de version Fixe pour ces projets. L' ensemble des projets change de version en même temps.

Quelques projets dit 'ext' sont placés dans une autre arborescence avec des versions fixes car ils ne bougent plus.

Utiliser un build incrémental

Ce plugin permet de détecter si la recompilation est nécessaire. Ce plugin a été fait ici.

http://maven-incremental-build.java.net/site/index.html

Faire du TDD

Avec des tests unitaires, pas question de build, tout se passe dans l'IDE. Et je ne m'attarde pas sur les nombreux intérêts de cette pratique.

Mettre en places des circuits courts pour la partie présentation

Le build peut simplement être évité au cour du developement, suivant la technologie utilisée:

  • jsp/js: Faire du war:inplace lorsque cela est possible, ou alors faire les modifications dans le repertoire de deploiment utilisé par le serveur (sans oublier de répercuter les modifs - OK ce n'est pas idéal)
  • GWT: Se placer en mode dévelopement pour éviter la compilation GWT
  • Code serveur/EJB: Se brancher en debug. Le code peut être remplacé à chaud tant que les signatures de méthode ne changent pas.

Détecter les modifications pour builder moins

Le job construit la commande maven en se basant sur le changelog, afin de ne builder que les projets qui ont changé, et les projets dépendants.

Mieux connaître l'avancement du build

Un plugin nommé progress-maven-plugin de mon cru permet d'ajouter un log de ce type:

Reactor Progress: 32/60 (53.33%) /workspace/module/subModule

Cela permet d'ajouter du feedback:

  • sur un build local: un 53,33% permet de définir assez précisement la durée de la pause café :)
  • sur le build hudson: Nous sommes sur des jobs de type FreeStyle, et pas Maven, donc nous n'avons pas l'avancement module par module. D'autres part, les calculs faits par hudson pour prédire la durée du job est faussé par l'aspect dynamique de nos jobs (voir 'détecter les modifications'). Cela est surtout utile lorsque le build est claimé et que la correction est en cours de build.

Générer le Mind Map des relations

Comme un dessin vaut 10 000 mots, il est interessant d'avoir le graphe des dépendances maven. IL existe plusieurs plugin qui génèrent une image, mais à partir d'une taille limite, l'image devient inutilisable. L'interêt de l'avoir sous forme de mindmap, c'est que l'on peut l'ouvrir avec l'outil de son choix, le parcourir, le modifier, afin d'en extraire l'information voulue.

http://blog.xebia.fr/2011/05/05/le-mind-mapping-applique-aux-dependances-des-projets-mavenises/

 

In Progress

Fixer les versions

Déplacer quelques projets en 'ext' et fixer la version pour ne plus les builder ni les télécharger plusieurs fois.

Casser des dépendances

Puisque notre build détecte le modifications et les propage, il devient critique de ne pas avoir de gros projet utilisés par de nombreux autres projets. Le risque est en effet de builder les projets qui ont une dépendance même s'il n'en utilise qu'une infime partie. Il faut donc continuer à découper, spécialiser les projets afin de builder juste.

Passer à Maven 3

C'est je pense un gros gain possible, mais quelques plugin maven ne sont pas compatibles, et n'ont pas encore été apadptés.

Essayer Jenkins

A ma connaissance, il n'y a pas de gain de performance particulier à obtenir. Ce qui fait la différence, c'est le nombre de plugin et l'activité de la communauté.

 

To Do

Parralléliser les tests

Cela nécessite d'avoir des tests bien indépendants, sans ordre, ni resources partagées, ni données en base réutilisées.

http://maven.apache.org/plugins/maven-surefire-plugin/test-mojo.html#parallel

Parralléliser le build

Une fois passé à Maven3, il est possible de parralléliser les builds à l'interieur du réacteur, en définnissant la taille du pool de threads.

https://cwiki.apache.org/confluence/display/MAVEN/Parallel+builds+in+Maven+3

Passer les jobs en type Maven

En supprimant la partie script non-maven du job, nous bénéficierons de la vue du build en cours avec le statut de chaque module.

Automatiser la génération du mind Map

Créer un job permettant de générer le mind map et le publier sur le serveur d'intégration continuer, afin de pouvoir consulter la version la plus récente sans le générer en local.

Atteindre le build incassable

Réaliser un build pre-commit.

http://blog.javabien.net/2009/12/01/serverless-ci-with-git/

http://blog.octo.com/integration-continue-performante-part-2/

Parralléliser le déploiement

Nos serveur d'intégration sont déployés en série, rendant la plateforme indisponnible pendant 15min à chaque déploiement (arrêt, copie, démarrage des 2 * 3 serveurs).

Faire du war:inplace partout

Mettre en place le mode de dévelopement inplace sur tous les projets web jsp.

 

Conclusion

Chouchoutez votre build pour vous faciliter la vie.

Aucun commentaire:

Enregistrer un commentaire

Feedback...