martes, 12 de julio de 2011

Cluster JBoss con Session Replication

En esta entrega os explicare como armar un cluster de servidores de aplicaciones Java con replicacion de sesion. He elegido JBoss porque me place (?).

Elementos

*1 aplicacion desarrollada en Java
*2 o mas servidores JBoss ya instalados. En mi caso son dos y los voy a llamar application1(192.168.70.249) y application2 (192.168.70.250)
*1 o mas servidores Apache (en mi caso son dos) con mod_jk instalado

Se asume que se parte desde una instalacion funcionando (standalone) y una aplicacion tambien funcionando. La idea es pasar de un servidor a un cluster de servidores... De todas maneras en la practica es bastante complicado y tedioso hacer este tipo de migraciones, pero me parece que vale la pena compartirlo.

Para que JBoss funcione en modo cluster se deben colocar los arhivos a desplegar en el directorio $JBOSS_HOME/server/all/deploy en cada servidor del cluster. Tambien se podria poner en el directorio $JBOSS_HOME/server/all/farm que hace el deploy automatico entre todos los nodos del cluster.

Luego, hay que modificar el script de inicio, que seria asi, por ejemplo para el servidor 1


#!/bin/bash

/usr/local/jboss/bin/run.sh -b 192.168.70.249 -c all  >/dev/null 2>&1 &

echo servicio jboss iniciado...
y modificar el arhivo de configuracion $JBOSS_HOME/bin/run.conf. En negrita esta el parametro a agregar en cada nodo del cluster:

if [ "x$JAVA_OPTS" = "x" ]; then
   JAVA_OPTS="-Xms512m -Xmx3000m  -XX:PermSize=256m -XX:MaxPermSize=512m -Dsun.rmi.dgc.client.gcInterval=3600000 -Djboss,partition.name=cluster
-Dsun.rmi.dgc.server.gcInterval=3600000 -Duser.timezone=GMT-03:00"
Luego, en cada instancia de jboss modificar el archivo $JBOSS_HOME/server/all/deploy/jboss-web.deployer/server.xml y agregar en la siguiente linea lo que se muestra en negrita:
  
< Engine name="jboss.web" defaultHost="localhost" jvmRoute="worker1" >


En mi caso worker1 es el servidor application1.

Ahora se le debe indicar a JBoss que vamos a usar un balanceador (mod_jk). Para esto editar el archivo $JBOSS_HOME/server/all/deploy/jboss-web.deployer/META-INF/jboss-service.xml y agregar en la siguiente linea lo que se muestra en negrita:
 < attribute name="UseJK" >true< /attribute >
 Ahora, descomprimir el archivo ear a hacer deploy y editar el archivo /WEB-INF/web.xml. Agregar lo que esta en negrita:
el parameto se debe agregar dentro del contexto y NO DENTRO DE OTRO, sino NO FUNCIONA.

< web-app
        version="2.5"
        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_2_5.xsd" >
       
       
       
    < distributable/ >

Luego, editar el archivo /WEB-INF/jboss-web.xml, y agregar lo siguiente:
< jboss-web >
 
   < replication-config >
     < replication-trigger >SET_AND_NON_PRIMITIVE_GET< /replication-trigger >
     < replication-granularity >SESSION< /replication-granularity >
    < replication-field-batch-mode >true< /replication-field-batch-mode >
     < /replication-config >

< /jboss-web >
Yo utilice SESSION replication que es lo que necesitaba, para mas info... http://docs.jboss.org/jbossas/docs/Server_Configuration_Guide/beta500/html/clustering-http-app.html


Segurizando la consola jmx

Como la replicacion entre los servidores esta hecha por medio de jms, se precisa de la consola de jboss para monitorear la replicacion se debe segurizar, de lo contrario cualquier usuario sin autenticar puede reiniciar el servidor, editar configuraciones, etc.
Editar el archivo $JBOSS_HOME/server/all/conf/login-config.xml y agregar:

       < application-policy name = "jmx-console" >
                < authentication >
                < login-module code="org.jboss.security.auth.spi.UsersRolesLoginModule"
                             flag = "sufficient" >
        < module-option name="usersProperties" >props/jmx-console-users.properties< /module-option >
        < module-option name="rolesProperties" >props/jmx-console-roles.properties< /module-option >
        < /login-module >
        < /authentication >
        < /application-policy >
        < application-policy
                name="other" >
                < authentication >
                        < login-module
                                code="org.jboss.security.auth.spi.UsersRolesLoginModule"
                                flag="required" />
                < /authentication >
        < /application-policy >
Ahora, se debe editar el archivo $JBOSS_HOME/server/all/conf/props/jmx-console-users.properties (en el caso que no exista crearlo)

# A sample users.properties file for use with the UsersRolesLoginModule
admin=password_del_admin
Y tambien el archivo $JBOSS_HOME/server/all/conf/props/jmx-console-roles.properties

# A sample roles.properties file for use with the UsersRolesLoginModule
admin=JBossAdmin,HttpInvoker
En el caso de utilizar otro usuario que no sea admin, cambiarlo.

Configuracion de Apache:

Para hacer el balanceo de carga se utiliza Apache con el modulo mod_jk.
La instalacion de mod_jk requiere los siguientes paquetes (y sus dependencias que se instalaran automaticamente). Esto para CentOS / RedHat / Fedora

yum install -y httpd-devel gcc
Se baja el modulo a compilar


wget http://apache.dattatec.com//tomcat/tomcat-connectors/jk/tomcat-connectors-1.2.32-src.tar.gz
se descomprime, se compila y se instala en cada servidor apache.

tar -xzvf tomcat-connectors-1.2.32-src.tar.gz
cd tomcat-*
./configure --with-apxs=/usr/sbin/apxs
./make
./make install
 ahora editar el archivo /etc/httpd/conf.d/workers.properties. Este archivo es el de configuracion del balanceador de carga, aqui se van a definir los nodos del cluster, el peso para distribuir el trabajo, etc

#esta es la ruta de $JBOSS_HOME
workers.tomcat_home=/usr/local/jboss
#ruta a la jdk de la aplicacion
workers.java_home=/usr/local/java
#slash (en el caso de linux / en el caso de windows \)
ps=/
#lista de workers, router seria el cluster, status es para chequear estado de los servidores
worker.list=router,status
#defino nodo 1
worker.worker1.port=8009
worker.worker1.host=192.168.70.249
worker.worker1.socket_timeout=300
worker.worker1.type=ajp13
#defino el nodo 2
worker.worker2.port=8009
worker.worker2.host=192.168.70.250
worker.worker2.socket_timeout=300
worker.worker2.type=ajp13
#defino la carga (este parametro es relacional, es decir que si a cada nodo le pongo 1, distribuira la carga 1 a 1, si el nodo 1 tiene 10 y el nodo 2 tiene 1, la relacion de trabajo es 10 a 1)
worker.worker1.lbfactor=1
worker.worker2.lbfactor=1
#defino tipo de balanceo (lb=loadbalancing) 
worker.router.type=lb
worker.router.balance_workers=worker1,worker2
#defino que la sesion persista en cada worker
worker.router.sticky_session=1
worker.inprocess.type=jni
worker.status.type=status
Por ultimo, se define el virtual host y como sera montado por apache, en /etc/httpd/conf.d/vhosts.conf 
#Cargo el modulo compilado anteriormente
LoadModule jk_module modules/mod_jk.so
NameVirtualHost *
ServerName nombredelservidor
ServerSignature Off
#llamo a workers.properties
JkWorkersFile /etc/httpd/conf.d/workers.properties
# Defino los logs
JkLogFile /var/log/httpd/mod_jk.log
# log level [debug/error/info]
JkLogLevel debug
# Formato de log
JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories
kRequestLogFormat "%w %V %T"
JkShmFile /var/log/httpd/jk.shm
ServerAlias 1.2.3.4
ServerAdmin support@pepe.com
DocumentRoot /var/www/vhosts/
ErrorLog logs/cluster_error
CustomLog logs/cluster-access_log common
#envio los requests al cluster (llamado router) JkMount * router


Esto es todo por hoy amiguitos, cualquier duda, puteada o lo que quieran me avisan.
Un saludo a todos los que me conocen