Ir al contenido principal

Tomcat Cluster en Debian 7 (Wheezy)

Pues nos hemos animado a crear un cluster de tomcat. La verdad es muy sencillo hacerlo, simplemente habilitas unas opciones que ya vienen en tomcat y configuras mod_jk en apache para que administre el cluster y haga el balanceo de cargas. Muy, muy fácil, el detalle está en que no tienes alta disponibilidad, razón por la que puse el cluster en primer lugar. ¿Y entonces? Pues me puse a investigar, ya probé LiveRebel, y funciona de maravilla, pero igual te cobran... Así que busqué un poco más y di con mod_cluster de RedHat. Esta herramienta te permite lo mismo que mod_jk, pero le agrega alta disponibilidad, ¿a qué me refiero con alta disponibilidad? Al hecho de que cuando hay que hacer un redeploy de la aplicación si estas con mod_jk, apache no va a darse cuenta y te va a seguir enviando al tomcat que está haciendo el redeploy, y el cliente recibe el error de que no hay nada ahí, lo que sí hace mod_jk es notar que una instancia de tomcat ha sido dada de baja, entonces para lograr alta disponibilidad cuando necesitas actualizar alguna aplicación tendrías que detener la instancia en la que vas a hacer la actualización, actualizar mientras está detenida y levantar la instancia para que tome los cambios, de esta forma el apache con mod_jk si va a redirigir el tráfico a la instancia que este activa mientras la otra se esta actualizando. El problema es que si tienes una buena cantidad de aplicaciones spring/grails el server toma su buena cantidad de tiempo para reiniciar. En fin, no me pareció práctico, con mod_cluster resuelves este problema, las instancias le avisan a apache que están haciendo un redeploy y apache cambia todos los clientes de esta instancia a algún otra, por lo que el cliente no pierde su sesión y puede seguir trabajando sin problema.
Hice el intento de hacerlo trabajar con java 8, pero todavía está muy inestable, se caía de cuando en cuando, por lo que puse java 7, la otra cosa que intenté fue echarlo a andar con Tomcat 8, pero tampoco funcionó porque mod_cluster usa unas funciones que ya no están en Tomcat 8, por lo que tuve que usar la siguiente infraestructura:

  • Debian 7
  • apache 2.2.22 (instalado con aptitude)
  • tomcat 7.0.52
  • java 7 (1.7.0_51)
  • mod_cluster 1.2.6.Final

Todo lo tengo instalado en un solo servidor, apache hace de balanceador de cargas y único punto de entrada a las dos instancias de tomcat que tengo.
Para instalarlo hay que bajar los binarios para tu apache (en mi caso fue el x64) y el java bundle de mod_cluster. Los binarios de apache (*.so) van en donde están tus binarios en apache. En Debian 7 se encuentran en /usr/lib/apache2/modules y creas los archivos /etc/apache2/mods-available/cluster.load y /etc/apache2/mods-available/cluster.conf

<IfModule manager_module>
Listen 192.168.1.47:9999
ManagerBalancerName mycluster
<VirtualHost 192.168.1.47:9999>
KeepAliveTimeout 60
MaxKeepAliveRequests 0
AdvertiseFrequency 5
ServerAdvertise on
EnableMCPMReceive
#LogLevel debug
<Location />
Order deny,allow
Allow from 192.168.1
</Location>
<Location /cluster-manager>
SetHandler mod_cluster-manager
Order deny,allow
Allow from 192.168.1
</Location>
</VirtualHost>
</IfModule>
view raw cluster.conf hosted with ❤ by GitHub
LoadModule proxy_module /usr/lib/apache2/modules/mod_proxy.so
LoadModule proxy_ajp_module /usr/lib/apache2/modules/mod_proxy_ajp.so
LoadModule slotmem_module /usr/lib/apache2/modules/mod_slotmem.so
LoadModule manager_module /usr/lib/apache2/modules/mod_manager.so
LoadModule proxy_cluster_module /usr/lib/apache2/modules/mod_proxy_cluster.so
LoadModule advertise_module /usr/lib/apache2/modules/mod_advertise.so
view raw cluster.load hosted with ❤ by GitHub

Luego hay que ejecutar como root la instrucción:
a2enmod mod_cluster
Para habilitarlo.
Ahora necesitas copiar las librerías del java bundle de mod_cluster en el lib de cada instancia de tomcat que vayas a usar. En el bundle viene una libreria para tomcat7 y otra para tomcat6, usa la de tomcat7 y no pongas la de tomcat6. Y luego modificas los archivos server.xml de cada instancia de tomcat en ${INSTANCIA_TOMCAT}/conf/server.xml

<?xml version='1.0' encoding='utf-8'?>
<!--
Hay que cambiar todos los puertos si va a usar el mismo servidor, no hay que configurarlos en ningun otro lugar
porque la instancia le va a decir al apache mediante mensajes que tienen entre ellos.
-->
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<Listener className="org.apache.catalina.core.JasperListener" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
<!-- Agregar esta linea -->
<Listener className="org.jboss.modcluster.container.catalina.standalone.ModClusterListener" proxyList="192.168.1.47:9999" advertise="true" />
<GlobalNamingResources>
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
<!-- Cambiar el nombre de jvmRoute a algo distinto por instancia -->
<Engine name="Catalina" defaultHost="localhost" jvmRoute="instance1">
<!-- Asegurarse de que esta linea no este comentada si desea tener esta instancia como parte de un cluster -->
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log." suffix=".txt"
pattern="%h %l %u %t &quot;%r&quot; %s %b" />
</Host>
<!-- Y si soporta virtual hosts, si no usas virtual hosts no necesitas estas 3 lineas -->
<Host name="test.davidmendoza.org" appBase="vhosts/test"
unpackWARs="true" autoDeploy="true">
</Host>
</Engine>
</Service>
</Server>
view raw server.xml hosted with ❤ by GitHub

Es necesario iniciar apache primero y luego las instancias de tomcat, puedes revisar que aplicaciones estan publicadas en http://192.168.1.47:9999/cluster-manager.
Si haces cambios en tomcat no es necesario reiniciar apache (de eso se trata la alta disponibilidad), pero si haces cambios en apache, las instancias de tomcat pierden su conexión con apache y no se van a encontrar, es necesario reiniciar las instancias de tomcat cada vez que reinicies apache.

Comentarios

Entradas más populares de este blog

OpenSolaris, Clúster de Glassfish y Sun Java Web Server Loadbalancer

Pues estuve necesitando un clúster de Glassfish V2U2 para lo cual encontré rápidamente mucha información en Internet, el que más me gustó fue un blog de Ryan Wilson , pero también necesitaba poner el balanceador de cargas ( loadbalancer ) asi que para eso utilicé la documentación de Glassfish . Aquí el resúmen: Instalar OpenSolaris 200805 y despues realizar lo que les sugieren en los Release Notes , en donde te dicen que actualices su herramienta para instalar paquetes. NOTA: Antes de hacer esto, asegurarse de tener todas las máquinas que van a participar dentro del cluster mapeadas con un DNS, de no ser esto posible sus archivos de hosts deben de tener la información suya y de cada una de las máquinas que van a participar. (Gracias a equipo Telcel) Despues de esto seguir las instrucciones de Ryan . Con esto vas a tener el cluster de glassfish funcionando. Solo que en la configuración del segundo servidor puedes hacer lo siguiente para evitar los pasos 4 al 6 (lo siguiente todo en una...

Reporte Excel con JasperReports

Pues no funcionó el reporte con Jasper, pude hacer que evitara paginar con estas opciones ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); JRXlsExporter exporterXLS = new JRXlsExporter(); exporterXLS.setParameter(JRXlsExporterParameter.JASPER_PRINT, jasperPrint); // exporterXLS.setParameter(JRXlsExporterParameter.IS_DETECT_CELL_TYPE, Boolean.TRUE); exporterXLS.setParameter(JRXlsExporterParameter.IS_WHITE_PAGE_BACKGROUND, Boolean.FALSE); exporterXLS.setParameter(JRXlsExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS, Boolean.TRUE); exporterXLS.setParameter(JRXlsExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_COLUMNS, Boolean.TRUE); exporterXLS.setParameter(JRXlsExporterParameter.IS_COLLAPSE_ROW_SPAN, Boolean.TRUE); exporterXLS.setParameter(JRXlsExporterParameter.IGNORE_PAGE_MARGINS, Boolean.TRUE); exporterXLS.s...

JQuery Image Upload en Spring MVC

Utilizar el jQuery File Upload de blueimp  en Grails es una delicia. Pero necesito hacer una aplicación grande y no sé lo suficiente como para mantenerla óptima dentro de Grails, así que decidí portarla a Spring MVC, pero no encontré una implementación de esta herramienta en Java que hiciera lo que hace el plugin, que simplemente implementa lo que la herramienta ya hace en otras plataformas. Así que me puse a implementarla y ya quedó. La pueden encontrar en github ... Sólo necesitan clonarla, y ejecutarla con maven: mvn tomcat7:run