web-dev-qa-db-fra.com

La réplication de cluster/session de Tomcat ne se réplique pas correctement

Je suis en train de configurer le clustering/réplication sur Tomcat 7 sur mon ordinateur local, afin de l'évaluer pour une utilisation avec mon environnement/codebase.

Installer

J'ai deux serveurs Tomcat identiques dans des annuaires frères s'exécutant sur des ports différents. J'ai httpd qui écoute sur deux autres ports et qui se connecte aux deux instances de Tomcat en tant qu'hôtes virtuels. Je peux accéder et interagir avec les deux environnements sur les ports configurés; tout fonctionne comme prévu.

La mise en cluster des serveurs Tomcat est activée comme ceci, dans le fichier server.xml:

   <Cluster className="org.Apache.catalina.ha.tcp.SimpleTcpCluster"
             channelSendOptions="8">

      <Manager className="org.Apache.catalina.ha.session.DeltaManager"
               expireSessionsOnShutdown="false"
               notifyListenersOnReplication="true"/>

      <Channel className="org.Apache.catalina.tribes.group.GroupChannel">
        <Membership className="org.Apache.catalina.tribes.membership.McastService"
                    address="228.0.0.4"
                    port="45564"
                    frequency="500"
                    dropTime="3000"/>
        <Receiver className="org.Apache.catalina.tribes.transport.nio.NioReceiver"
                  address="auto"
                  port="4001"
                  autoBind="100"
                  selectorTimeout="5000"
                  maxThreads="6"/>

        <Sender className="org.Apache.catalina.tribes.transport.ReplicationTransmitter">
          <Transport className="org.Apache.catalina.tribes.transport.nio.PooledParallelSender"/>
        </Sender>
        <Interceptor className="org.Apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
        <Interceptor className="org.Apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
      </Channel>

      <Valve className="org.Apache.catalina.ha.tcp.ReplicationValve"
             filter=""/>
      <Valve className="org.Apache.catalina.ha.session.JvmRouteBinderValve"/>

      <Deployer className="org.Apache.catalina.ha.deploy.FarmWarDeployer"
                tempDir="/tmp/war-temp/"
                deployDir="/tmp/war-deploy/"
                watchDir="/tmp/war-listen/"
                watchEnabled="false"/>

      <ClusterListener className="org.Apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
      <ClusterListener className="org.Apache.catalina.ha.session.ClusterSessionListener"/>
   </Cluster>

et j'ai ajouté la balise distribuable au tout début de web.xml:

<web-app xmlns="http://Java.Sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://Java.Sun.com/xml/ns/javaee
                      http://Java.Sun.com/xml/ns/javaee/web-app_3_0.xsd"
  version="3.0">
  <distributable />

  (lots more...)

</web-app>

Ce qui fonctionne

Lorsque les serveurs démarrent, ils se connectent

Sep 16, 2013 1:44:23 PM org.Apache.catalina.ha.tcp.SimpleTcpCluster startInternal
INFO: Cluster is about to start
Sep 16, 2013 1:44:23 PM org.Apache.catalina.tribes.transport.ReceiverBase getBind
FINE: Starting replication listener on address:10.0.0.100
Sep 16, 2013 1:44:23 PM org.Apache.catalina.tribes.transport.ReceiverBase bind
INFO: Receiver Server Socket bound to:/10.0.0.100:4001
Sep 16, 2013 1:44:23 PM org.Apache.catalina.tribes.membership.McastServiceImpl setupSocket
INFO: Setting cluster mcast soTimeout to 500
Sep 16, 2013 1:44:23 PM org.Apache.catalina.tribes.membership.McastServiceImpl waitForMembers
INFO: Sleeping for 1000 milliseconds to establish cluster membership, start level:4
Sep 16, 2013 1:44:24 PM org.Apache.catalina.tribes.membership.McastServiceImpl waitForMembers
INFO: Done sleeping, membership established, start level:4
Sep 16, 2013 1:44:24 PM org.Apache.catalina.tribes.membership.McastServiceImpl waitForMembers
INFO: Sleeping for 1000 milliseconds to establish cluster membership, start level:8
Sep 16, 2013 1:44:25 PM org.Apache.catalina.tribes.membership.McastServiceImpl waitForMembers
INFO: Done sleeping, membership established, start level:8

Lorsque le deuxième serveur démarre, le premier enregistre

Sep 16, 2013 2:17:30 PM org.Apache.catalina.tribes.group.interceptors.TcpFailureDetector messageReceived
FINE: Received a failure detector packet:ClusterData[src=org.Apache.catalina.tribes.membership.MemberImpl[tcp://{10, 0, 0, 100}:4000,{10, 0, 0, 100},4000, alive=112208, securePort=-1, UDP Port=-1, id={118 6 107 -67 88 98 72 95 -73 41 4 -108 58 -5 -127 -41 }, payload={}, command={}, domain={}, ]; id={25 110 120 -2 -25 6 78 -97 -84 -34 2 -11 49 -62 -8 -56 }; sent=2013-09-16 14:17:30.139]
Sep 16, 2013 2:17:30 PM org.Apache.catalina.tribes.transport.nio.NioReplicationTask remoteEof
FINE: Channel closed on the remote end, disconnecting
Sep 16, 2013 2:17:30 PM org.Apache.catalina.tribes.membership.McastServiceImpl memberDataReceived
FINE: Mcast add member org.Apache.catalina.tribes.membership.MemberImpl[tcp://{10, 0, 0, 100}:4001,{10, 0, 0, 100},4001, alive=1010, securePort=-1, UDP Port=-1, id={82 -45 -109 -56 -110 -5 78 -10 -103 61 -40 -59 -36 -79 104 120 }, payload={}, command={}, domain={}, ]
Sep 16, 2013 2:17:30 PM org.Apache.catalina.ha.tcp.SimpleTcpCluster memberAdded
INFO: Replication member added:org.Apache.catalina.tribes.membership.MemberImpl[tcp://{10, 0, 0, 100}:4001,{10, 0, 0, 100},4001, alive=1011, securePort=-1, UDP Port=-1, id={82 -45 -109 -56 -110 -5 78 -10 -103 61 -40 -59 -36 -79 104 120 }, payload={}, command={}, domain={}, ]

et quand on est arrêté, l'autre enregistre

Sep 16, 2013 2:28:05 PM org.Apache.catalina.tribes.membership.McastServiceImpl memberDataReceived
FINE: Member has shutdown:org.Apache.catalina.tribes.membership.MemberImpl[tcp://{10, 0, 0, 100}:4001,{10, 0, 0, 100},4001, alive=422279, securePort=-1, UDP Port=-1, id={54 43 17 -9 13 -11 72 -63 -107 -78 -8 65 -21 -77 115 88 }, payload={}, command={66 65 66 89 45 65 76 69 88 ...(9)}, domain={}, ]
Sep 16, 2013 2:28:05 PM org.Apache.catalina.tribes.group.interceptors.TcpFailureDetector memberDisappeared
INFO: Verification complete. Member disappeared[org.Apache.catalina.tribes.membership.MemberImpl[tcp://{10, 0, 0, 100}:4001,{10, 0, 0, 100},4001, alive=422279, securePort=-1, UDP Port=-1, id={54 43 17 -9 13 -11 72 -63 -107 -78 -8 65 -21 -77 115 88 }, payload={}, command={66 65 66 89 45 65 76 69 88 ...(9)}, domain={}, ]]
Sep 16, 2013 2:28:05 PM org.Apache.catalina.ha.tcp.SimpleTcpCluster memberDisappeared
INFO: Received member disappeared:org.Apache.catalina.tribes.membership.MemberImpl[tcp://{10, 0, 0, 100}:4001,{10, 0, 0, 100},4001, alive=422279, securePort=-1, UDP Port=-1, id={54 43 17 -9 13 -11 72 -63 -107 -78 -8 65 -21 -77 115 88 }, payload={}, command={66 65 66 89 45 65 76 69 88 ...(9)}, domain={}, ]

donc je sais qu'ils se connaissent.

Enfin, lorsque j’utilise le MBean Cluster/Operations dans jconsole pour essayer de définir la propriété "foo" sur "bar", jconsole signale la méthode "invoquée avec succès" et les journaux du serveur.

Sep 16, 2013 2:30:18 PM org.Apache.catalina.ha.tcp.SimpleTcpCluster setProperty
WARNING: Dynamic setProperty(foo,value) has been disabled, please use explicit properties for the element you are trying to identify

Je ne m'inquiète pas trop de cette erreur; la plupart du temps inclus pour démontrer que setProperty crée une instruction de journal.

Ce qui ne fonctionne pas

Autant que je sache, aucune information de session n'est répliquée dans mon application.

Le gestionnaire Tomcat ne répertorie que les sessions démarrées sur le serveur qu’il surveille, et pas sur l’autre du cluster.

J'ai l'impression que, chaque fois que l'application appelle HttpSession.setAttribute, cet attribut doit être répliqué sur les autres nœuds de la grappe et je m'attendrais à ce qu'un enregistrement de celui-ci soit consigné. Mon application comprend cette ligne:

   public static void saveBillingInfo(IPageContext pageContext, BillingInfo billingInfo)
   {    
      pageContext.getSession().setAttribute("billingInfo", billingInfo);
      //etc...
   }

où BillingInfo est une classe Serializable ne contenant qu'un seul champ, un tableau de hachage contenant des informations sur les informations de facturation.

Aucune instruction de journal n'est écrite lors du traitement de cette ligne ou de toute autre ligne, et je ne vois aucune preuve indiquant que les informations de session sont réellement partagées.

Toutes les suggestions ou autres questions sont les bienvenues.

18
nvioli

Nous avons eu ce problème identique. Bien que cela n’ait été documenté nulle part ailleurs, ce qui m’avait été résolu, c’était de déplacer simplement la balise <Manager> de server.xml vers le fichier global context.xml (en la faisant sortir du groupe <Serveur> ... <Cluster> ... le groupe <Context>). Dès que nous avons fait cela, tout "par magie" a commencé à fonctionner. Ceci ne s’appliquait qu’à Tomcat 7 ... Tomcat 6 fonctionnait parfaitement avec la configuration décrite ci-dessus (et décrite dans la documentation).

<Context>
    <Manager className="org.Apache.catalina.ha.session.DeltaManager"
             expireSessionsOnShutdown="false"
             notifyListenersOnReplication="true" />
</Context>

Maintenant, supprimez simplement la balise <Manager> de votre groupe de cluster dans server.xml et vous avez terminé.

29
Jason

sur server.xml, ajoutez simplement:

<Cluster className="org.Apache.catalina.ha.tcp.SimpleTcpCluster"
             channelSendOptions="6"/>  

et dans votre fichier context.xml:

<Manager className="org.Apache.catalina.ha.session.DeltaManager"
         expireSessionsOnShutdown="false"
         notifyListenersOnReplication="true" />

cela a fonctionné pour moi, j'utilise Tomcat 7 et Tomcat 8

1
Fabian Mejia

Selon la documentation Tomcat, vous devez effectuer l'une de ces deux tâches (PAS les deux): 

  1. Spécifiez dans web.xml <distributable/> pour activer la mise en cluster et utilisez le <Manager> par défaut spécifié dans le fichier server.xml ou ...

  2. Ajouter un <Manager> au niveau de l'application dans context.xml

0
user6649882

Si vous souhaitez activer le clustering pour une application déployée spécifique, vous pouvez utiliser l'exemple ci-dessous. 

server.xml

  <Host name="localhost"  appBase="webapps"
        unpackWARs="true" autoDeploy="true">

      <Channel className="org.Apache.catalina.tribes.group.GroupChannel">
        <Membership className="org.Apache.catalina.tribes.membership.McastService"
                    address="228.0.0.4"
                    port="45564"
                    frequency="500"
                    dropTime="3000"/>
        <Receiver className="org.Apache.catalina.tribes.transport.nio.NioReceiver"
                  address="auto"
                  port="4000"
                  autoBind="100"
                  selectorTimeout="5000"
                  maxThreads="6"/>

        <Sender className="org.Apache.catalina.tribes.transport.ReplicationTransmitter">
          <Transport className="org.Apache.catalina.tribes.transport.nio.PooledParallelSender"/>
        </Sender>
        <Interceptor className="org.Apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
        <Interceptor className="org.Apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
      </Channel>

      <Valve className="org.Apache.catalina.ha.tcp.ReplicationValve"
             filter=""/>
      <Valve className="org.Apache.catalina.ha.session.JvmRouteBinderValve"/>

      <Deployer className="org.Apache.catalina.ha.deploy.FarmWarDeployer"
                tempDir="/tmp/war-temp/"
                deployDir="/tmp/war-deploy/"
                watchDir="/tmp/war-listen/"
                watchEnabled="false"/>

      <ClusterListener className="org.Apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
      <ClusterListener className="org.Apache.catalina.ha.session.ClusterSessionListener"/>

      <Manager className="org.Apache.catalina.ha.session.DeltaManager"
       expireSessionsOnShutdown="false"
       notifyListenersOnReplication="true"/>

    <Resource auth="Container" driverClassName="Oracle.jdbc.OracleDriver" factory="com.atomikos.Tomcat.EnhancedTomcatAtomikosBeanFactory" minPoolSize="4" maxPoolSize="50" name="jdbc/myoracle/myconect" password="sdfhsfghsgfsfg" type="com.atomikos.jdbc.nonxa.AtomikosNonXADataSourceBean" uniqueResourceName="uniresource" url="jdbc:Oracle:thin:@10.10.10.10.:1521:abc" user="user"/>
    </Context>
0
Thanh Nguyen

Notre solution a été d’ajouter la balise <distributable/> au fichier WEB-INF/web.xml sous l’élément <web-app>. Je ne sais pas pourquoi cela a fonctionné pour nous et non pour le PO.

À propos, la solution de Jason a également fonctionné pour nous.

0
David I