Guillaume VIEL :: java jee tomcat linux

Aller au contenu | Aller au menu | Aller à la recherche

mercredi 4 janvier 2012

Log4j avec Spring et applications multiples dans Tomcat

Je déploie habituellement les applications web dans Tomcat en multi-instance avec une instance Tomcat par application (ceux qui croient que c'est une hérésie iront voir les concepteurs de Tomcat Mark Thomas et Filip Hanik qui préconisent eux mêmes cette solution). Cependant, dans certains contextes, et notamment chez certains clients, les contraintes font que l'on est obligé de faire autrement...

Dans le cas présent, c'est la configuration de log4j via Spring qui pose (encore) problème : je déploie 2 applications identiques (avec configuration applicative légèrement différente) sous 2 contextes différents dans le même serveur Tomcat. Se posent donc 2 problèmes :

  • il faut pouvoir packager l'application sous des formes différentes et notamment 2 contextes différents : /my-app1 et /my-app2, donc paramétrer le packaging
  • la configuration log4j est à priori identique pour ces 2 applications (packages identiques) : ceci pose le problème de la séparation des logs (et éventuellement la différenciation des niveaux de log)

Lire la suite...

mercredi 13 octobre 2010

Tomcat : configuration proxy HTTPS

La configuration d'un proxy HTTPS pour Tomcat est plus cohérente que celle de maven et plus directe; il suffit juste d'indiquer les propriétés système de Java dans le fichier $CATALINA_HOME/conf/catalina.properties :

http.proxyHost=proxy.mydomain.com
http.proxyPort=8080
http.nonProxyHost=localhost|10.*

https.proxyHost=proxy.mydomain.com
https.proxyPort=8080

lundi 3 mai 2010

Maven optimiser le déploiement avec un WAR éclaté

Optimiser le temps de déploiement devient parfois crucial pour éviter de perdre des heures... Après avoir tenté des plugins maven (comme cargo par exemple) sans être totalement convaincu par leur efficacité (quand ça marche!), il m'a semblé plus efficace de recourir au script shell.

Maven est idéal pour toutes ces tâches mais nécessite parfois un peu de tuning, notamment lorsqu'on lui demande le packaging de l'application avec le plugin maven-war-plugin. L'opération est laborieuse et nécessite ensuite le déploiement d'un WAR ce qui veut dire que (de façon raccourcie car maven fait plus de choses en réalité) :

  • maven compile l'application
  • Maven copie les classes compilées et les fichiers de ressource dans une structure éclaté (dans le répertoire target)
  • Maven zippe le tout dans un WAR (et c'est long!)
  • ensuite il faut uploader le WAR vers le serveur cible
  • Tomcat ou votre serveur d'application java doit ensuite dézipper l'archive...
Au final vous avez plusieurs opérations couteuses en temps et en ressource. Tout doit être fait manuellement.

Comment accélérer le processus ?

Julien DUBOIS propose sur le blog de Responcia une solution intéressante pour optimiser vos développements avec Jetty. Il apporte la preuve en vidéo que l'on peut améliorer les productivité des développements Java de cette façon. Mais parfois, il n'est pas possible d'opter pour Jetty...

Lire la suite...

mercredi 24 mars 2010

Configuration d'un pool de connexions JDBC avec Oracle RAC

La documentation Oracle FCF (Fast Connection Failover) pour configurer un pool de connexion JDBC avec un cluster Oracle RAC 10g est plutôt obscure et manque d'exemple...

Après quelques tâtonnements et en fouillant un peu, voici une configuration sous Tomcat à mettre dans le context.xml de l'application web ou dans server.xml (déconseillé sauf en ressource globale) qui semble plaire à Oracle :

    <Resource name="jdbc/myRacDb" auth="Container"
            type="oracle.jdbc.pool.OracleDataSource"
            factory="oracle.jdbc.pool.OracleDataSourceFactory"
            description="My Oracle RAC DB"
            user="myschema" password="mypass"
            url="jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=rac1.mydomain.com)(PORT=1521))(ADDRESS=(PROTOCOL=TCP)(HOST=rac2.mydomain.com)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=myservice.mydomain.com)))"
            driverClassName="oracle.jdbc.OracleDriver"
            maxActive="10"
            maxIdle="5"
            minIdle="2"
            maxWait="5000"
            connectionCacheName="myCache"
            connectionCachingEnabled="true"
            fastConnectionFailoverEnabled="true"
            onsConfigStr="nodes=rac1.mydomain.com:4200,rac2.mydomain.com:4200"
            connectionProperties="oracle.jdbc.ReadTimeout=30000" />

Cette datasource est accessible via le JNDI sous le nom java:comp/env/jdbc/myRacDb (sous Tomcat).

Le cluster Oracle RAC est ici composé de 2 noeuds rac1.mydomain.com et rac2.mydomain.com. On travaille avec un driver Oracle thin.

Sous tomcat, il faut mettre la librairie Oracle JDBC ons.jar (Oracle Notification Services) dans le common/lib (du moins sous tomcat 5) avec les autres librairies Oracle (ojdbc14.jar et orai18n.jar notamment).

Afin de ne pas avoir d'ennuis, il est obligatoire de mettre l'attribut nodes dans l'onsConfigString et préférable qu'il soit à l'identique de la configuration Oracle (pour cela une bonne communication avec votre DBA est nécessaire).

Nous avons surtout tâtonné pour trouver le type et la factory car la documentation n'est pas orienté tomcat mais plutôt grand serveurs d'applications commerciaux (je vous laisse deviner lesquels!).

Si vous faites des déploiements à chaud sur Tomcat (déconseillé) il est préférable d'enlever le connectionCacheName pour éviter que Tomcat se plaigne de l'existence d'un cache portant le même nom (apparemment pas de nettoyage à chaud!) : vous serez alors obligé de redémarrer votre serveur Tomcat.

mercredi 10 juin 2009

JVM 1.5.0_10 crash en mode remote debugging

Apparemment il est possible de faire crasher très simplement une JVM en mode debug. Je viens de le constater sur un serveur Tomcat qui était en mode debug (cf billet sur remote debugging tomcat) sur le port 8000, il suffit tout simplement de lancer une requête HTTP sur celui-ci pour faire planter la JVM :

ERROR: transport error 202: handshake failed - received >GET / HTTP/1.1< - excepted >JDWP-Handshake< ["transport.c",L41]
JDWP exit error JVMTI_ERROR_NONE(0): could not connect, timeout or fatal error

Il est donc vivement conseillé de ne pas mettre vos serveurs en production en mode debug... On vous aura prévenu...

Le bug est connu http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6339385


jeudi 20 mars 2008

Monitoring JVM Tomcat 5 avec jconsole, tunnel SSH et firewall...

Dans billet du 16 mars je présentais un monitoring java avec VisualGC. En réalité, cela n'était qu'une mise en bouche par rapport à ce qui suit... En effet, jconsole, l'outil fournit en standard dans le JDK Sun a aussi tout ce qu'il faut pour réaliser un monitoring Java. Il n'est disponible qu'à partir de java 5.
En fait jconsole est utile en phase de développement. Pour un monitoring persistent, il faudra plutôt s'orienter vers des solutions comme Munin par exemple qui permet une collecte et historisation des données dans le temps, avec surtout le stockage de ces données. Toutes les données jconsole sont perdues lors de l'arrêt de la JVM. Je vais présenter ici un nième exemple de monitoring de Tomcat par jconsole en connexion non sécurisée, Dans l'entête de votre bin/catalina.sh mettez ceci (les lignes en commentaire correspondent justement à celle qui seraient susceptibles de faire marcher le SSL) :

JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote"
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.authenticate=false"
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.port=8889"
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.ssl=false" echo $JAVA_OPTS

jmxremote.authenticate=false : permet d'indiquer que l'on ne veut pas utiliser le fichier de password (jmxremote.password.file)
jmxremote.port=8889 : indique le port sur lequel on va se connecter avec jconsole
jmxremote.ssl=false : désactive le SSL

Ensuite, sur un client disposant d'un JDK on peut lancer jconsole comme suit :
$ jconsole mytomcathost:8889 &


Je lance un appel à ceux ou celles qui auraient réussi une connexion remote en SSL entre jconsole et le serveur à monitorer, car, oui, je l'avoue, mes nombreux essais en suivant scrupuleusement la doc Sun, que ce soit sous linux, voire sous windows (si! si! je passe de temps à autre sous cet OS...), n'ont jamais abouti! Et après de nombreuses recherches, aucun article sur internet ne semble présenter une solution qui fonctionne avec SSL. Si vous avez la solution je suis preneur : envoyez moi l'article! Les lignes suivantes seraient à ajouter :

#JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.password.file=/home/tomcat/jmxremote.password"
#JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.ssl.need.client.auth=true"
#JAVA_OPTS="$JAVA_OPTS -Djavax.net.ssl.keyStore=/home/tomcat/.keystore"
#JAVA_OPTS="$JAVA_OPTS -Djavax.net.ssl.keyStorePassword=changeit"

* UPDATE 15/11/2008 : aurais-je oublié ceci : com.sun.management.jmxremote.registry.ssl=true ??? *

Pour contourner ce problème ainsi que la lourdeur de mise en oeuvre d'une connexion SSL (génération des certificats), on peut utiliser sur une plateforme de type linux d'autres outils qui peuvent prendre en charge la sécurité. Parmi les alternatives possibles, seul le tunneling SSH (avec échange de la clé publique vers le serveur cible) pourra fonctionner, moyennant quelques manipulations manuelles supplémentaires. Car en réalité, ceci n'est pas aussi simple qu'il n'y parait. Si l'on exécute les commandes suivantes sur la machine client :

ssh -L18889:localhost:8889 my.remote.tomcat.host
jconsole localhost:18889

on s'aperçoit en fait que cela ne fonctionne pas... Eh oui : côté serveur 2 ports supplémentaires aléatoires de valeur N et N+1 sont en écoute pour le RMI registry en plus du port jmxremote.port :

$ netstat -tlnp | grep java
tcp6 0 0 ::ffff:127.0.0.1:8006 :::* LISTEN 5374/java
tcp6 0 0 :::8889 :::* LISTEN 5374/java
tcp6 0 0 :::8009 :::* LISTEN 5374/java
tcp6 0 0 :::8080 :::* LISTEN 5374/java
tcp6 0 0 :::40882 :::* LISTEN 5374/java
tcp6 0 0 :::40883 :::* LISTEN 5374/java

jconsole essaye alors de se connecter sur les ports N=40882 et N+1 en localhost sur la machine cliente alors qu'il accède bien grâce à SSH par port forwarding au port 8889! Si vous êtes pressé, la solution consiste à créer 2 tunnels SSH supplémentaires vers ces ports :

ssh -L40882:localhost:40882 my.remote.tomcat.host
ssh -L40883:localhost:40883 my.remote.tomcat.host

Cette méthode n'est pas très "propre", nécessite des opérations manuelles pour trouver les ports dynamiques dès que vous redémarrez votre serveur et ne fonctionnera pas dans un environnement avec certaine configuration de firewall (il faut aussi ajouter -Djava.rmi.server.hostname=localhost au niveau serveur)...

J'ai finalement trouvé sur un des blogs Sun un article intéressant à ce sujet : Connecting Through Firewall Using JMX - Without modifying the server application

Dans cet article Daniel Fuchs explique comment créer son propre JVM agent auquel on pourra passer en option un port fixe.

Liens : Monitoring and Management Using JMX | Monitoring Applications through a Firewall | Keytool documentation

mercredi 19 mars 2008

Remote debugging avec Eclipse d'une application web sous Tomcat

Le débogage d'application web est pénible et qui n'a pas été usé par l'utilisation intensive de traces qui au final n'apportent rien, si ce n'est de pourrir un peu plus l'application et la rendre encore moins performante qu'avant...
Une des solutions pour remédier au problème est probablement le débogage à distance. Celui qui concernera le plus de monde sera probablement le débogage d'une application web sous Tomcat. Elle est très simple à mettre en place. Il suffit d'activer JPDA au niveau de la JVM qui lance le conteneur java et d'indiquer le port sur lequel le client de débogage (Eclipse) pourra se connecter.
Les options JVM sont généralement les suivantes :

Lire la suite...