56 votes

Meilleures pratiques pour déployer des applications web Java avec un minimum de temps d'arrêt ?

Lors du déploiement d'une grande application Web Java (>100 Mo .war), j'utilise actuellement le processus de déploiement suivant :

  • Le fichier .war de l'application est développé localement sur la machine de développement.
  • L'application étendue est rsync:ée de la machine de développement vers l'environnement réel.
  • Le serveur d'applications dans l'environnement réel est redémarré après le rsync. Cette étape n'est pas strictement nécessaire, mais j'ai constaté que le redémarrage du serveur d'applications lors du déploiement évite le message "java.lang.OutOfMemoryError : PermGen space" dû au chargement fréquent des classes.

Les points positifs de cette approche :

  • Le rsync minimise la quantité de données envoyées de la machine de développement vers l'environnement réel. Le téléchargement de l'ensemble du fichier .war prend plus de dix minutes, alors qu'une rsync ne prend que quelques secondes.

Les points négatifs de cette approche :

  • Pendant que le rsync est en cours d'exécution, le contexte de l'application est redémarré puisque les fichiers sont mis à jour. Idéalement, le redémarrage devrait avoir lieu après la fin du rsync, et non pendant son exécution.
  • Le redémarrage du serveur d'applications entraîne un temps d'arrêt d'environ deux minutes.

Je voudrais trouver un processus de déploiement avec les propriétés suivantes :

  • Temps d'arrêt minimal pendant le processus de déploiement.
  • Temps minimal consacré au téléchargement des données.
  • Si le processus de déploiement est spécifique au serveur d'applications, ce dernier doit être open-source.

Question :

  • Compte tenu des exigences énoncées, quel est le processus de déploiement optimal ?

30voto

Asaph Points 56989

Mise à jour :

Depuis que cette réponse a été écrite, une meilleure façon de déployer des fichiers war sur tomcat sans temps d'arrêt a émergé. Dans les versions récentes de tomcat, vous pouvez inclure les numéros de version dans les noms de vos fichiers war. Ainsi, par exemple, vous pouvez déployer les fichiers ROOT##001.war y ROOT##002.war au même contexte simultanément. Tout ce qui suit le ## est interprété comme un numéro de version par tomcat et ne fait pas partie du chemin du contexte. Tomcat maintiendra toutes les versions de votre application en cours d'exécution et servira les nouvelles demandes et sessions à la plus récente version qui est complètement opérationnelle tout en terminant gracieusement les anciennes demandes et sessions sur la version avec laquelle elles ont commencé. La spécification des numéros de version peut également être effectuée via le gestionnaire de tomcat et même les tâches ant de catalina. Plus d'informations ici .

Réponse originale :

Rsync a tendance à être inefficace sur les fichiers compressés puisque son algorithme de transfert delta recherche les changements dans les fichiers et qu'un petit changement dans un fichier non compressé peut modifier radicalement la version compressée résultante. Pour cette raison, il peut être judicieux de rsynchroniser un fichier de guerre non compressé plutôt qu'une version compressée, si la bande passante du réseau s'avère être un goulot d'étranglement.

Qu'y a-t-il de mal à utiliser l'application Tomcat manager pour effectuer vos déploiements ? Si vous ne voulez pas télécharger le fichier war entier directement vers l'application Tomcat manager à partir d'un emplacement distant, vous pouvez le rsynchroniser (non compressé pour les raisons mentionnées ci-dessus) vers un emplacement de remplacement sur la boîte de production, le reconditionner en war, puis le remettre au manager localement. Il existe une tâche ant agréable qui est livrée avec Tomcat et qui vous permet de faire des déploiements script en utilisant l'application Tomcat manager.

Il y a un défaut supplémentaire dans votre approche que vous n'avez pas mentionné : Pendant que votre application est partiellement déployée (au cours d'une opération rsync), votre application pourrait être dans un état incohérent où les interfaces modifiées peuvent être désynchronisées, les dépendances nouvelles/mises à jour peuvent être indisponibles, etc. De plus, en fonction de la durée de votre tâche rsync, votre application peut en fait redémarrer plusieurs fois. Savez-vous que vous pouvez et devez désactiver le comportement d'écoute des fichiers modifiés et de redémarrage dans Tomcat ? Ce n'est en fait pas recommandé pour les systèmes de production. Vous pouvez toujours effectuer un redémarrage manuel ou par script de votre application en utilisant l'application Tomcat manager.

Votre application ne sera pas disponible pour les utilisateurs pendant un redémarrage, bien sûr. Mais si vous êtes si préoccupé par la disponibilité, vous avez sûrement des serveurs web redondants derrière un équilibreur de charge. Lors du déploiement d'un fichier war mis à jour, vous pourriez demander temporairement à l'équilibreur de charge d'envoyer toutes les requêtes aux autres serveurs web jusqu'à ce que le déploiement soit terminé. Rincez et répétez pour vos autres serveurs Web.

20voto

Stephen C Points 255558

Il a été remarqué que rsync ne fonctionne pas bien lorsque l'on apporte des modifications à un fichier WAR. La raison en est que les fichiers WAR sont essentiellement des fichiers ZIP et que, par défaut, ils sont créés avec des fichiers membres compressés. De petites modifications apportées aux fichiers membres (avant la compression) entraînent des différences d'échelle importantes dans le fichier ZIP, ce qui rend l'algorithme de transfert delta de rsync inefficace.

Une solution possible est d'utiliser jar -0 ... pour créer le fichier WAR original. Le site -0 L'option indique à la jar pour ne pas compresser les fichiers membres lors de la création du fichier WAR. Ensuite, lorsque rsync compare l'ancienne et la nouvelle version du fichier WAR, l'algorithme de transfert delta devrait être capable de créer de petites différences. Faites ensuite en sorte que rsync envoie les différences (ou les fichiers originaux) sous forme compressée ; utilisez par exemple rsync -z ... ou un flux de données compressé / transport en dessous.

EDIT : Selon la façon dont le fichier WAR est structuré, il peut également être nécessaire d'utiliser la fonction jar -0 ... pour créer des fichiers JAR de composants. Cela s'applique aux fichiers JAR qui sont fréquemment soumis à des modifications (ou qui sont simplement reconstruits), plutôt qu'aux fichiers JAR stables de tiers.

En théorie, cette procédure devrait apporter une amélioration significative par rapport à l'envoi de fichiers WAR ordinaires. En pratique, je n'ai pas essayé, je ne peux donc pas promettre que cela fonctionnera.

L'inconvénient est que le fichier WAR déployé sera beaucoup plus gros. Cela peut entraîner un allongement du temps de démarrage des applications Web, mais je pense que l'effet sera marginal.


Une approche totalement différente consisterait à examiner votre fichier WAR pour voir si vous pouvez identifier les JAR de bibliothèque qui ne changeront probablement (presque) jamais. Retirez ces JARs du fichier WAR et déployez-les séparément dans le fichier common/lib par exemple, en utilisant rsync .

13voto

ideasculptor Points 740

Dans tout environnement où les temps d'arrêt sont à prendre en considération, vous utilisez sûrement une sorte de grappe de serveurs pour augmenter la fiabilité par la redondance. Je sortirais un hôte du cluster, je le mettrais à jour, puis je le remettrais dans le cluster. Si vous avez une mise à jour qui ne peut pas être exécutée dans un environnement mixte (changement de schéma incompatible requis sur la base de données, par exemple), vous allez devoir arrêter tout le site, au moins pour un moment. L'astuce consiste à mettre en place les processus de remplacement avant d'abandonner les originaux.

En utilisant tomcat comme exemple - vous pouvez utiliser CATALINA_BASE pour définir un répertoire où se trouveront tous les répertoires de travail de tomcat, séparément du code exécutable. Chaque fois que je déploie un logiciel, je le déploie dans un nouveau répertoire de base afin que le nouveau code réside sur le disque à côté de l'ancien. Je peux ensuite démarrer une autre instance de tomcat qui pointe vers le nouveau répertoire de base, tout démarrer et fonctionner, puis échanger l'ancien processus (numéro de port) avec le nouveau dans l'équilibreur de charge.

Si je suis soucieux de préserver les données de session sur le commutateur, je peux configurer mon système de telle sorte que chaque hôte ait un partenaire auquel il réplique les données de session. Je peux laisser tomber l'un de ces hôtes, le mettre à jour, le faire remonter pour qu'il récupère les données de session, puis commuter les deux hôtes. Si j'ai plusieurs paires dans le cluster, je peux laisser tomber la moitié de toutes les paires, puis effectuer une commutation de masse, ou je peux le faire une paire à la fois, selon les exigences de la version, les exigences de l'entreprise, etc. Personnellement, cependant, je préfère permettre aux utilisateurs finaux de subir la perte très occasionnelle d'une session active plutôt que d'essayer d'effectuer une mise à niveau avec des sessions intactes.

Il s'agit d'un compromis entre l'infrastructure informatique, la complexité du processus de publication et l'effort des développeurs. Si votre cluster est assez grand et votre désir assez fort, il est assez facile de concevoir un système qui peut être remplacé sans aucun temps d'arrêt pour la plupart des mises à jour. Les changements de schéma importants nécessitent souvent un temps d'arrêt réel, car le logiciel mis à jour ne peut généralement pas s'adapter à l'ancien schéma, et vous ne pouvez probablement pas vous en sortir en copiant les données dans une nouvelle instance de base de données, en effectuant la mise à jour du schéma, puis en basculant les serveurs sur la nouvelle base de données, car vous aurez perdu toutes les données écrites dans l'ancienne base de données après que la nouvelle ait été clonée. Bien sûr, si vous disposez des ressources nécessaires, vous pouvez charger les développeurs de modifier la nouvelle application afin d'utiliser les nouveaux noms de tables pour toutes les tables mises à jour, et vous pouvez mettre en place des déclencheurs sur la base de données active qui mettront correctement à jour les nouvelles tables avec les données écrites dans les anciennes tables par la version précédente (ou peut-être utiliser des vues pour émuler un schéma à partir de l'autre). Mettez en place vos nouveaux serveurs d'applications et insérez-les dans le cluster. Il y a une tonne de jeux que vous pouvez jouer afin de minimiser les temps d'arrêt si vous avez les ressources de développement pour les construire.

Le mécanisme le plus utile pour réduire les temps d'arrêt lors des mises à jour logicielles consiste peut-être à s'assurer que votre application peut fonctionner en mode lecture seule. Cela permettra à vos utilisateurs de disposer de certaines fonctionnalités nécessaires, mais vous laissera la possibilité d'effectuer des changements à l'échelle du système qui nécessitent des modifications de la base de données, etc. Placez votre application en mode lecture seule, puis clonez les données, mettez à jour le schéma, mettez en place de nouveaux serveurs d'applications sur la nouvelle base de données, puis modifiez l'équilibreur de charge pour utiliser les nouveaux serveurs d'applications. Le seul temps d'arrêt est le temps nécessaire pour passer en mode lecture seule et le temps nécessaire pour modifier la configuration de votre équilibreur de charge (la plupart d'entre eux peuvent le gérer sans aucun temps d'arrêt).

10voto

cetnar Points 6170

Mon conseil est d'utiliser rsync avec les versions éclatées mais de déployer un fichier war.

  1. Créez un dossier temporaire dans l'environnement réel où vous aurez la version éclatée de webapp.
  2. Versions éclatées de Rsync.
  3. Après avoir réussi le rsync, créez un fichier war dans un dossier temporaire sur la machine de l'environnement live.
  4. Remplacez l'ancien war dans le répertoire de déploiement du serveur par le nouveau war du dossier temporaire.

Le remplacement de l'ancienne guerre par la nouvelle est recommandé dans le conteneur JBoss (qui est basé sur Tomcat) car c'est une opération atomique et rapide et il est certain que lorsque le déployeur démarrera, l'application entière sera dans un état déployé.

8voto

jarnbjo Points 18238

Ne pouvez-vous pas faire une copie locale de l'application web actuelle sur le serveur web, rsync vers ce répertoire et ensuite, peut-être même en utilisant des liens symboliques, en une seule fois, faire pointer Tomcat vers un nouveau déploiement sans beaucoup de temps d'arrêt ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X