Mejorando la disponibilidad de nuestros entornos Java

Son muchos los entornos Java que están configurados con Apache web server actuando como front-end y Apache Tomcat como contenedor JSP/Servlet. Es lógico pensar que en estos entornos se van a encontrar desplegadas varias aplicaciones y por desgracia, no todas funcionan de igual forma en cuanto a estabilidad y robustez se refiere. En varias ocasiones me he encontrado con administradores de sistemas que optan por programar tareas para reiniciar los servicios con cierta periodicidad y otros que optan por aislar las aplicaciones “problemáticas” en contenedores específicos. Así por lo menos evitan que las aplicaciones que funcionan correctamente no se vean perjudicadas por el resto. Es evidente que siendo este el escenario la disponibilidad de nuestros servicios corre un grave peligro. En muy pocas ocaciones me he encontrado con que el servidor web o la base de datos hayan sido el origen del problema.

Teniendo en cuenta este escenario, creo que existen soluciones muy fáciles de implementar y con resultados muy óptimos. A continuación una ilustración para explicar la solución propuesta:

Ilustración sobre la solución propuesta

De la ilustración se deduce que la solución se centra en la disponibilidad del contenedor y/o servidor de aplicaciones JEE. De las tres capas, -creo- que es la que más problemas de disponibilidad presenta. Más adelante nos centraremos en el resto de capas. La idea básica de esta solución consiste en tener una instancia de nuestro contenedor y/o servidor de aplicaciones (y aplicaciones) replicado para respaldar al que está funcionando. Nuestro Apache webserver atenderá las peticiones y en función de la petición, estas se reenviarán a SERVER 2. Si por cualquier motivo, el SERVER 2 dejase de funcionar, Apache webserver sabría que tiene que enviar esas mismas peticiones a SERVER 1.

¿Qué conseguimos con esta solución?

  1. Evitar prácticas que aislen las aplicaciones problemáticas.
  2. Una solución no intrusiva porque no hemos tenido que tocar nada en nuestras aplicaciones, es decir, es una solución válida incluso para aplicaciones antiguas.
  3. En entornos virtualizados resulta muy cómodo y fácil de mantener.
  4. Si SERVER 1 y SERVER 2 comparten un sistema de ficheros, un más fácil.
  5. Evitar prácticas que consistan en reiniciar los sistemas antes de que estos degraden completamente.
  6. Si a esta solución le añadimos software como NAGIOS, los administradores de sistemas estarán informados de las caídas y podrán actuar en consecuencia.
  7. Aumentar la disponibilidad de nuestro entorno.

¿Qué no conseguimos con esta solución?

  1. Compartir las sesiones entre los servidores.
  2. Compartir las conexiones de acceso a datos.
  3. Alta disponibilidad del entorno completo.

Para conseguir esto necesitamos el conector mod_jk desarrollado dentro del proyecto Apache Tomcat. Suponiendo que ya tenemos nuestro Apache webserver instalado y configurado, veamos qué tenemos que hacer para compilar mod_jk:

  1. wget http://www.apache.org/dist/tomcat…
  2. cd tomcat-connectors-1.2.26-src/native
  3. ./configure –with-apxs=/opt/httpd-2.2.8/bin/apxs (directorio de ejemplo)
  4. make
  5. cp apache-2.0/.libs/mod_jk.so /opt/httpd-2.2.8/modules

Ahora habilitamos el módulo en Apache webserver:

  1. Editamos el archivo: /opt/httpd-2.2.8/conf/httpd.conf
  2. Añadimos las líneas:
    1. LoadModule jk_module modules/mod_jk.so
    2. Include conf/extra/mod_jk.conf

A continuación creamos los archivos de configuración para el conector:

  1. Creamos el archivo mod_jk.conf en /opt/httpd-2.2.8/conf/extra
  2. Creamos el archivo workers.properties en /opt/httpd-2.2.8/conf/extra

En el archivo mod_jk.conf configuraremos esas reglas correspondientes a las peticiones que atenderá Apache webserver y las cuales definirán a nuestras aplicaciones desplegadas en Apache Tomcat. Un ejemplo de este archivo sería:

JkLogFile logs/mod_jk.log
JkShmFile logs/mod_jk.shm
JkLogLevel info
JkWorkersFile conf/extra/workers.properties

# Add the jkstatus mount point
JkMount /jkmanager/* jkstatus

JkMount /opina/* router

Básicamente en este archivo se configura el archivo de log, el archivo para compartir información entre los conectores y las aplicaciones que queremos “conectar”. Concretamente jkmanager nos permitirá monitorizar cómo funcionan los conectores.

Y la configuración para los conectores:

# The advanced router LB worker
worker.list=router,jkstatus

# Define a worker using ajp13
worker.worker1.port=8009
worker.worker1.host=192.168.0.3
worker.worker1.type=ajp13
worker.worker1.lbfactor=1
# Define prefered failover node for worker1
worker.worker1.redirect=worker2

# Define another worker using ajp13
worker.worker2.port=8009
worker.worker2.host=192.168.0.4
worker.worker2.type=ajp13
worker.worker2.lbfactor=1
# Disable worker2 for all requests except failover
worker.worker2.activation=disabled

# Define the LB worker
worker.router.type=lb
worker.router.balance_workers=worker1,worker2

# Define a ‘jkstatus’ worker using status
worker.jkstatus.type=status

Con esta configuración todas las peticiones se enviarán al conector worker1, y si algo falla, se enviarán al conector worker2.

Evidentemente en esta solución caben varias mejoras, pero antes de mejorar en esta parte, me centraré en mejorar la publicación de contenido estático. Quizás nuestro amigo Apache webserver tenga que convivir con Cherokee o Lighttpd.

Las sugerencias siempre son bienvenidas.

One thought on “Mejorando la disponibilidad de nuestros entornos Java

  1. Pingback: NOTAS « Business World TI

Leave a Reply

Your email address will not be published. Required fields are marked *