Translate

sábado, 23 de julio de 2011

Receta para Alfresco en Cluster con replicación de sesión

Con la salida de la versión 3.4.3 de Alfresco Enterprise se ha solucionado un bug que arrastraba la configuración en cluster desde 2009. Finalmente se ha solucionado y voy a explicar paso a paso como se debe configurar utilizando el paquete en formato zip.

Alfresco de por si no replica las sesiones del usuario de un nodo a otro y de esto se debe encargar el servidor de alpicaciones. Por tanto debemos establecer el cluster no solo en Alresco si no también a nivel de Tomcat. En mis pruebas he seguido este esquema:

         Balanceador
        192.168.1.122
             |    
          Cluster      
        /         \        
    Tomcat1       Tomcat2  
192.168.1.122   192.168.1.12

  • Balanceador: Apache 2.2 + proxy_balancer + proxy_ajp
  • Cluster: Tomcat configurado mediante BackupManager
  • Tomcat1: Centos 5 con Tomcat 6.0.32
  • Tomcat2: Ubuntu con Tomcat 6.0.32 
En este esquema un nodo hace de servidor NFS y de balanceador. En un entorno en producción estos 2 elementos deberian ser independientes para garantizar que la caida de un nodo no afecte al otro. 
Creamos la estructura de directorios para la instalación
#mkdir -p /opt/alfresco/tomcat
#mkdir -p /opt/alfresco/indices
Tomcat:
#cd /opt/alfresco
#tar zxvf  /tmp/apache-tomcat-6.0.32.tar.gz
#ln -s apache-tomcat-6.0.32 tomcat
Copiamos el contenido del paquete de Alfresco
#unzip alfresco-enterprise-3.4.3.zip -d alfresco
#cp -rp /tmp/alfresco/web-server/* /opt/alfresco/tomcat
En esta copia a parte de los ficheros de Alfresco también se sobreescriben ficheros de configuración de Tomcat. Es necesario editar el fichero context.xml en destino puesto que el valor que tiene impide el funcionamiento del cluster. En el fichero context.xml debemos dejar comentada la línea:
 <!-- Uncomment this to disable session persistence across Tomcat restarts -->
 <!--Manager pathname="" /-->
Activamos el puerto AJP en ambos nodos descomentando en el fichero server.xml la linea
 <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
Configuramos el nombre de la ruta en la directiva Engine del fichero server.xml de los 2 nodos.  tomcat1:
 <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">
tomcat2:
 <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat2">
En este punto también vamos a configurar el Cluster de Tomcat tal como se indica en el manual de Apache Tomcat: http://tomcat.apache.org/tomcat-6.0-doc/cluster-howto.html Editamos el fichero server.xml dentro de la directiva <Engine>
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
                 channelSendOptions="6">

          <Manager className="org.apache.catalina.ha.session.BackupManager"
                   expireSessionsOnShutdown="false"
                   notifyListenersOnReplication="true"
                   mapSendOptions="6"/>
          <!--
          <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="5000"
                      selectorTimeout="100"
                      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"/>
            <Interceptor className="org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor"/>
          </Channel>

          <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
                 filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;"/>

          <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.ClusterSessionListener"/>
</Cluster>
Añadimos el tag distributable que permitirá la replicación de sesiones en el fichero web.xml de alfresco.war y share.war en ambos nodos al final del fichero:
.

.
<distributable/>
</web-app>
MySQL
tomcat1:
mysql> create database alfresco343;
mysql> grant all privileges on alfresco343.* to 'alfresco'@'%' identified by 'alfresco';
NFS
tomcat1:
/etc/exports
/opt/alfresco/alf_data 192.168.1.0/24(rw,no_root_squash,no_subtree_check,async) 
tomcat2:
#mount 192.168.1.122:/opt/alfresco/alf_data /opt/alfresco/alf_data
Apache tomcat1:
#a2enmod proxy_ajp proxy_balancer proxy
Configuramos el balanceo con los 2 nodos, incluyendo además el balancer-manager que nos permitirá monitorizar, activar y desactivar cada uno de los nodos para realizar las pruebas. Para ello he configurado 2 grupos diferentes de balanceo, uno para Alfresco y otro para Share, cada uno de manera distinta para ver las 2 posibles configuraciones en el fichero /etc/apache2/conf.d/proxyajp.conf
<Location /balancer-manager>
   SetHandler balancer-manager
</Location>

<Proxy balancer://balancer1>
   BalancerMember ajp://192.168.1.122:8009 route=tomcat1
   BalancerMember ajp://192.168.1.12:8009 route=tomcat2
   ProxySet stickysession=JSESSIONID
</Proxy>
ProxyPass /alfresco balancer://balancer1/alfresco
<Proxy balancer://balancer2>
   BalancerMember ajp://192.168.1.122:8009 route=tomcat1
   BalancerMember ajp://192.168.1.12:8009 route=tomcat2
</Proxy>
<Location /share>
ProxyPass balancer://balancer2/share stickysession=JSESSIONID
</Location>
alfresco-global.properties en tomcat2:
#alf_data compartido por nfs
dir.root=/opt/alfresco343/alf_data
#indices en local
dir.indexes=/opt/alfresco343/indices/lucene-indexes
dir.indexes.backup=/opt/alfresco343/indices/backup-lucene-indexes
dir.indexes.lock=/opt/alfresco343/indices/locks
.
.
alfresco.cluster.name=ALFCLUSTER
alfresco.jgroups.defaultProtocol=TCP
alfresco.tcp.initial_hosts=192.168.1.122[7800],192.168.1.12[7800]
alfresco.jgroups.bind_address=192.168.1.12
En el arranque veremos primero como se forma el cluster de tomcat
22-jul-2011 19:38:47 org.apache.catalina.core.StandardService start
INFO: Arrancando servicio Catalina
22-jul-2011 19:38:47 org.apache.catalina.core.StandardEngine start
INFO: Starting Servlet Engine: Apache Tomcat/6.0.32
22-jul-2011 19:38:47 org.apache.catalina.ha.tcp.SimpleTcpCluster start
INFO: Cluster is about to start
22-jul-2011 19:38:47 org.apache.catalina.tribes.transport.ReceiverBase bind
INFO: Receiver Server Socket bound to:/192.168.1.12:5000
22-jul-2011 19:38:47 org.apache.catalina.tribes.membership.McastServiceImpl setupSocket
INFO: Setting cluster mcast soTimeout to 500
22-jul-2011 19:38:47 org.apache.catalina.tribes.membership.McastServiceImpl waitForMembers
INFO: Sleeping for 1000 milliseconds to establish cluster membership, start level:4
22-jul-2011 19:38:48 org.apache.catalina.ha.tcp.SimpleTcpCluster memberAdded
INFO: Replication member added:org.apache.catalina.tribes.membership.MemberImpl[tcp://{192, 168, 1, 122}:5000,{192, 168, 1, 122},5000, alive=10519,id={80 9
4 82 -34 95 106 76 118 -85 119 -121 -44 -79 -105 -125 74 }, payload={}, command={}, domain={}, ]
y una vez arrancado Alfresco, el cluster de este:
19:39:29,778  INFO  [cache.jgroups.JGroupsKeepAliveHeartbeatReceiver]
New cluster view with additional members:
   Last View: null
   New View:  [tomcat1-59540|1] [tomcat1-59540, tomcat2-44982]

Una vez arrancados los 2 nodos y comprobando que Alfresco funciona vamos a abrir una pestaña nueva en el navegador con el balancer manager para poder ver en que nodo estamos y poder deshabilitarlo sin tener que parar ningún nodo:



Accediendo a http://192.168.1.122/share vemos que se ha generado tráfico en el worker del primer nodo, por tanto procedo a deshabilitarlo forzando el paso al segundo nodo.

Durate mis pruebas con Share la sesión se ha mantenido sin mostrarse ningún error. En el caso de Alfresco Explorer ha mostrado una pantalla de error de sesión expirada pero al volver a la aplicación ha recuperado la sesión.

Espero que esto os sirva!

3 comentarios:

  1. Excelente post Raúl, me lo guardo en favoritos. Muy completo y explicado paso a paso. Saludos y gracias por compartir tus conocimientos!

    ResponderEliminar
  2. ¿Has probado a no usar sticky session en el balanceador?

    ResponderEliminar
  3. No, pero debería funcionar sin sticky

    ResponderEliminar