Clustering Tomcat

Cette page a été rédigée il y a fort fort longtemps, et n'a pas tellement été mise à jour.

 

Vous savez, moi je ne crois pas qu'il y ait de bonne ou de mauvaise page. Moi, si je devais résumer mon wiki aujourd'hui avec vous, je dirais que c'est d'abord des rencontres. Des gens qui m'ont tendu la main, peut-être à un moment où je ne pouvais pas, où j'étais seul chez moi. Et c'est assez curieux de se dire que les hasards, les rencontres forgent une destinée... Parce que quand on a le goût de la chose, quand on a le goût de la chose bien faite, le beau geste, parfois on ne trouve pas l'interlocuteur en face je dirais, le miroir qui vous aide à avancer. Alors ça n'est pas mon cas, comme je disais là, puisque moi au contraire, j'ai pu ; et je dis merci au wiki, je lui dis merci, je chante le wiki, je danse le wiki... je ne suis qu'amour ! Et finalement, quand des gens me disent « Mais comment fais-tu pour avoir cette humanité ? », je leur réponds très simplement que c'est ce goût de l'amour, ce goût donc qui m'a poussé aujourd'hui à entreprendre une construction logicielle... mais demain qui sait ? Peut-être simplement à me mettre au service de la communauté, à faire le don, le don de soi.

L’installation de Tomcat en cluster est théoriquement simple et sobrement expliqué sur le site de Tomcat.

Pour résumer, il faut ajouter un élément <Cluster> dans le <Engine> ou le <Host> :

<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>

Simple, non ? Malheureusement, cela ne fonctionne pas toujours. N’est-ce pas Kilicool ? J’ai rencontré deux cas où il a fallu affiner cette configuration : un cluster avec deux instances de Tomcat sur la même machine, Windows ou Linux, et un cluster sous Linux. Cet article a été réalisé et testé avec Tomcat 6.

Configuration par défaut

En déclarant le cluster avec cette simple ligne, il faut être conscient qu’on met en place plusieurs éléments dans leur configuration par défaut.

Tomcat-cluster.png

Cette architecture du composant cluster se retrouve lorsqu’on utilise une configuration détaillée du Cluster.

Channel

Les éléments les plus délicats à configurer sont ceux du Channel. Ce sont eux qui assurent les communications entre les instances du cluster.

  • Membership communique en multicast pour découvrir d’autres membres sur la même adresse et le même port de multicast (228.0.0.4:45564, par défaut). Chaque instance envoie à cette adresse, sa propre adresse IP et le port sur lequel écoute le Receiver.

  • Receiver écoute sur un port (4000, par défaut) et réceptionne les changements d’états envoyés par les autres instances.

  • Sender envoie les changements d’état qui ont été réalisés sur sa propre instance. Il envoie ces changements à toutes les membres qui ont été découverts.

Manager

Le manager est le gestionnaire de session. Il remplace le Manager par défaut, en ajoutant des capacités de réplication. Bien que moins compliqué que le Channel, celui-ci nous a posé quelques soucis.

En effet, nous avions désactivé la persistance des sessions en activant la ligne du Manager dans le fichier conf/context.xml de Tomcat.

 <Context>
   <Manager pathname="" />
 </Context>

Le problème, c’est que ce fichier est chargé après conf/server.xml, il écrase donc la définition du manager faite dans le Cluster. On s’est donc retrouvés avec des instances qui se trouvent, mais des applications qui n’échangent rien. Il ne faut donc pas activer cette ligne de configuration.

Cluster mono-machine

Gestion des ports

Tout d’abord, pour démarrer deux instances de Tomcat sur une même machine, il faut résoudre les conflits de ports. En plus des ports classiques (HTTP 8080, AJP 8009, SHUTDOWN 8005,…​), il faut gérer le port du Receiver. Au passage, on va éviter des problèmes ultérieurs en branchant explicitement le Receiver sur l’adresse localhost.

           <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
                     address="localhost" port="4100"
                     autoBind="100" selectorTimeout="5000" maxThreads="6"/>

Ceci permet de démarrer les instances de Tomcat sur la même machine, mais ne leur permet pas de communiquer entre elles. Je n’ai pas d’explication certain, mais je pense que le dysfonctionnement vient du fait qu’un paquet multicast envoyé envoyés depuis une adresse IP n’est pas renvoyé vers la même adresse. Pour faire fonctionner ce cluster, il faut donc basculer vers une définition statique des membres du cluster, ou plutôt, ajouter une définition statique car la découverte dynamique reste active.

StaticMembership

Pour déclarer statiquement des membres, il faut ajouter un intercepteur de type StaticMembershipInterceptor dans lequel on peut ajouter un ou plusieurs membres.

           <Interceptor className="org.apache.catalina.tribes.group.interceptors.StaticMembershipInterceptor">
               <Member className="org.apache.catalina.tribes.membership.StaticMember"
                       host="localhost" port="4200"
                       securePort="-1" domain="local-domain"
                       uniqueId="{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}"/>
           </Interceptor>

On reporte, et adapte cette configuration sur chaque instance du cluster. Résultat : les sessions des applications clusterisées sont répliquée.

Cluster Linux

L’objectif étant assez rarement de monter un cluster mono-machine, on peut estimer que cette recette est très peu utile. En fait, elle est utile dès qu’on veut déployer un cluster dans un environnement qui ne supporte pas le multicast. C’est généralement le cas dans des environnements WAN, car les routeurs internet ne laissent pas passer ce type de trafic. C’est le cas, aussi, sur certains systèmes, qui n’activent pas forcément le multicast par défaut.

Dans ce cas, deux solutions nous sont offertes : passer en membership statique ou activer le multicast.

Toutes ces questions nous avons dû nous les poser en déployer Tomcat en cluster en environnement Linux.

Linux et multicast

En fouinant sur les forums, on s’est posé cette première question : est-ce que nos connexions réseau sont compatibles avec le multicast ? Pour y répondre, un petit ifconfig nous informe :

 $ ifconfig eth1
 eth1    Link encap:Ethernet  HWaddr 08:00:27:e6:28:d4
         inet adr:192.168.56.52  Bcast:192.168.56.255  Masque:255.255.255.0
         adr inet6: fe80::a00:27ff:fee6:28d4/64 Scope:Lien
         UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
         ...

Cette dernière ligne nous indique que, pour eth1, c’est OK.

Ensuite, est-ce que les paquets multicast sont envoyés au bon endroit, par la bonne interface réseau. Pour cela, on peut utiliser la commande route.

 $ route
 Destination     Passerelle      Genmask         Indic Metric Ref    Use Iface
 10.0.2.0        *               255.255.255.0   U     0      0        0 eth0
 192.168.56.0    *               255.255.255.0   U     0      0        0 eth1
 default         10.0.2.2        0.0.0.0         UG    0      0        0 eth0

On constate qu’il n’y a pas de route spécifiée pour les adresses de multicast, et que la route par défaut passe par eth0 et non par eth1. Il est probablement possible d’ajouter une route pour le multicast (route add 228.0.0.4 eth1), mais on peut se débrouiller sans. Il faut surtout demander au receveur d’écouter sur la bonne adresse IP, et désactiver l’adresse automatique :

           <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
                     address="192.168.56.52" port="4200"
                     autoBind="100" selectorTimeout="5000" maxThreads="6"/>

Cette solution a fonctionné dans le cluster avec deux machines virtuelles Debian 5, sous VirtualBox. Elle a aussi fonctionné dans l’environnement VMWare avec du Suse 11 de Kilicool. Par contre, je ne pourrais pas garantir son fonctionnement dans tous les environnements, la diversité des solutions apportées dans les forums en temoigne.