Cluster Glassfishv3 y mod_jk
0. Índice de contenidos.
- 1. Entorno
- 2. Introducción
- 3. Arquitectura y configuración de mod_jk
- 4. Instalación de glassfish y configuración de cluster
- 5. Aplicación
- 6. Despliegue
- 7. Prueba de balanceo
- 8. Problemas encontrados
- 9. Conclusiones
1. Entorno
Este tutorial está desarrollado usando el siguiente entorno:
- Hardware: Portátil MacBook Pro 2Ghz Intel Core i7 (4 núcleos) 8Gb de RAM
- Sistema Operativo: Mac OS X 10.7.2 (Lion)
- Eclipse Indigo (Revisar tutorial de Alex para su instalación)
- Oracle Glashfishv3
- Versión de java SDK 6 instalada en el sistema
- Maven3 instalado y configurado en el sistema
- Apache con mod_jk preconfigurado (se extenderá/modificará) (Consultar un ejemplo)
2. Introducción
A continuación veremos como realizar una configuración de un cluster local con Glassfish utilizando un Apache con mod_jk para el balanceo de peticiones.
3. Arquitectura y configuración de mod_jk
El objetivo de este tutorial será comprobar la escalabilidad y la réplica de sesión para una aplicación montada en JSF. La arquitectura de servidores será la siguiente:

La configuración de mod_jk será la siguiente:
workers.properties
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# Define la lista de workers que se usaran para mapear las peticiones worker.list=loadbalancer,status worker.maintain=2 # Configuración basica para todos los worker worker.basic.type=ajp13 worker.basic.socket_timeout=1 worker.basic.connect_timeout=100 worker.basic.ping_mode=A worker.basic.host=localhost worker.basic.lbfactor=1 # Definimos el Nodo1 worker.node1.reference=worker.basic worker.node1.port=8009 # Definimos el Nodo2 worker.node2.reference=worker.basic worker.node1.port=8010 #Definimos el balanceo de carga worker.loadbalancer.type=lb worker.loadbalancer.balance_workers=node1,node2 worker.loadbalancer.sticky_session=false worker.loadbalancer.retries=1 worker.status.type=status |
uriworkermap.properties
1 2 3 |
# Contexto de nuestra aplicacion ejemplo /jsfcluster=loadbalancer /jsfcluster/*=loadbalancer |
4. Instalación de glassfish y configuración de cluster
Lo primero que haremos será descargar una copia de glassfish desde la web: http://glassfish.java.net/es/downloads/3.0.1-final.html
Una vez descargado el archivo glassfish-3.0.1-unix-ml.sh (la versión para Mac), lo ejecutamos y seguiremos los siguientes pasos:









Ahora procederemos a iniciar la instancia creada de glashfish que utilizaremos como administradora del cluster.
Si no hemos realizado un update de glassfish, podemos realizarlo ejecutando <GLASHFISH_HOME>/bin/updatetool (donde <GLASHFISH_HOME> es la ruta configurada en el proceso de instalación), es bastante recomendable realizarlo para solucionar posibles problemas.
Abrimos un terminal, vamos a la ruta «<GLASHFISH_HOME>/glassfishv3/glassfish/bin» y ejecutamos «startserv» (si hemos updateado tendremos que ejecutar antes asadmin start-domain –upgrade en la misma ruta).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
MacBook-Pro-de-Carlos:bin cleon$ ./startserv 26-dic-2011 19:16:13 com.sun.enterprise.admin.launcher.GFLauncherLogger info INFO: L?nea de comandos de llamada de JVM: /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/bin/java -cp /Users/cleon/glassfishv3/glassfish/modules/glassfish.jar -XX:+UnlockDiagnosticVMOptions -XX:MaxPermSize=192m -XX:NewRatio=2 -XX:+LogVMOutput -XX:LogFile=/Users/cleon/glassfishv3/glassfish/domains/domain1/logs/jvm.log -Xmx512m -d32 -client -javaagent:/Users/cleon/glassfishv3/glassfish/lib/monitor/flashlight-agent.jar -Dfelix.fileinstall.disableConfigSave=false -Djavax.net.ssl.keyStore=/Users/cleon/glassfishv3/glassfish/domains/domain1/config/keystore.jks -Djava.awt.headless=true -Dfelix.fileinstall.poll=5000 -Djava.endorsed.dirs=/Users/cleon/glassfishv3/glassfish/modules/endorsed:/Users/cleon/glassfishv3/glassfish/lib/endorsed -Dfelix.fileinstall.bundles.startTransient=true -Djavax.net.ssl.trustStore=/Users/cleon/glassfishv3/glassfish/domains/domain1/config/cacerts.jks -Dcom.sun.enterprise.security.httpsOutboundKeyAlias=s1as -DANTLR_USE_DIRECT_CLASS_LOADING=true -Djava.security.auth.login.config=/Users/cleon/glassfishv3/glassfish/domains/domain1/config/login.conf -Dgosh.args=--noshutdown -c noop=true -Dosgi.shell.telnet.maxconn=1 -Djdbc.drivers=org.apache.derby.jdbc.ClientDriver -Dfelix.fileinstall.dir=/Users/cleon/glassfishv3/glassfish/modules/autostart/ -Dosgi.shell.telnet.port=6666 -Djava.security.policy=/Users/cleon/glassfishv3/glassfish/domains/domain1/config/server.policy -Dfelix.fileinstall.log.level=2 -Dosgi.shell.telnet.ip=127.0.0.1 -Dcom.sun.enterprise.config.config_environment_factory_class=com.sun.enterprise.config.serverbeans.AppserverConfigEnvironmentFactory -Dcom.sun.aas.instanceRoot=/Users/cleon/glassfishv3/glassfish/domains/domain1 -Dcom.sun.aas.installRoot=/Users/cleon/glassfishv3/glassfish -Djava.ext.dirs=/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/ext:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/jre/lib/ext:/Users/cleon/glassfishv3/glassfish/domains/domain1/lib/ext -Dfelix.fileinstall.bundles.new.start=true -Dfelix.fileinstall.debug=1 -Dorg.glassfish.web.rfc2109_cookie_names_enforced=false -Djava.library.path=/Users/cleon/glassfishv3/glassfish/lib:/Users/cleon/glassfishv3/glassfish/bin:/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java com.sun.enterprise.glassfish.bootstrap.ASMain -domainname domain1 -asadmin-args --host,,,localhost,,,--port,,,4848,,,--secure=false,,,--terse=false,,,--echo=false,,,--interactive=true,,,start-domain,,,--verbose=true,,,--debug=false,,,--domaindir,,,/Users/cleon/glassfishv3/glassfish/domains,,,domain1 -instancename server -verbose true -debug false -asadmin-classpath /Users/cleon/glassfishv3/glassfish/modules/admin-cli.jar -asadmin-classname com.sun.enterprise.admin.cli.AsadminMain -upgrade false -type DAS -domaindir /Users/cleon/glassfishv3/glassfish/domains/domain1 -read-stdin true 26-dic-2011 19:16:13 com.sun.enterprise.admin.launcher.GFLauncherLogger info INFO: Se ha iniciado correctamente en 12 mseg. Launching GlassFish on Felix platform 26-dic-2011 19:16:15 com.sun.enterprise.server.logging.LogManagerService postConstruct ADVERTENCIA: Record begin marker is not a proper value so using default. 26-dic-2011 19:16:15 com.sun.enterprise.server.logging.LogManagerService postConstruct ADVERTENCIA: Record end marker is not a proper value so using default. 26-dic-2011 19:16:15 com.sun.enterprise.server.logging.LogManagerService postConstruct ADVERTENCIA: Log Format field separator is not a character so using default. 26-dic-2011 19:16:15 com.sun.enterprise.server.logging.LogManagerService postConstruct ADVERTENCIA: Date Format specified is wrong so using default. [#|2011-12-26T19:16:15.474+0100|INFO|glassfish3.1.1|org.glassfish.ha.store.spi.BackingStoreFactoryRegistry|_ThreadID=10;_ThreadName=main;|Registered org.glassfish.ha.store.adapter.cache.ShoalBackingStoreProxy for persistence-type = replicated in BackingStoreFactoryRegistry|#] [#|2011-12-26T19:16:15.706+0100|INFO|glassfish3.1.1|javax.enterprise.system.core.com.sun.enterprise.v3.admin.adapter|_ThreadID=10;_ThreadName=main;|The Admin Console is already installed, but not yet loaded.|#] [#|2011-12-26T19:16:15.722+0100|INFO|glassfish3.1.1|javax.enterprise.system.core.com.sun.enterprise.v3.services.impl|_ThreadID=12;_ThreadName=Grizzly-kernel-thread(1);|Grizzly Framework 1.9.36 started in: 73ms - bound to [0.0.0.0:7676]|#] [#|2011-12-26T19:16:15.722+0100|INFO|glassfish3.1.1|javax.enterprise.system.core.com.sun.enterprise.v3.services.impl|_ThreadID=14;_ThreadName=Grizzly-kernel-thread(1);|Grizzly Framework 1.9.36 started in: 90ms - bound to [0.0.0.0:4848]|#] [#|2011-12-26T19:16:15.722+0100|INFO|glassfish3.1.1|javax.enterprise.system.core.com.sun.enterprise.v3.services.impl|_ThreadID=11;_ThreadName=Grizzly-kernel-thread(1);|Grizzly Framework 1.9.36 started in: 80ms - bound to [0.0.0.0:3700]|#] [#|2011-12-26T19:16:15.723+0100|INFO|glassfish3.1.1|javax.enterprise.system.core.com.sun.enterprise.v3.services.impl|_ThreadID=15;_ThreadName=Grizzly-kernel-thread(1);|Grizzly Framework 1.9.36 started in: 114ms - bound to [0.0.0.0:8080]|#] [#|2011-12-26T19:16:15.722+0100|INFO|glassfish3.1.1|javax.enterprise.system.core.com.sun.enterprise.v3.services.impl|_ThreadID=13;_ThreadName=Grizzly-kernel-thread(1);|Grizzly Framework 1.9.36 started in: 95ms - bound to [0.0.0.0:8181]|#] [#|2011-12-26T19:16:15.758+0100|INFO|glassfish3.1.1|javax.enterprise.system.core.com.sun.enterprise.v3.server|_ThreadID=10;_ThreadName=main;|GlassFish Server Open Source Edition 3.1.1 (12) tiempo de inicio: Felix (1.101ms), servicios de inicio(508ms), total(1.609ms)|#] [#|2011-12-26T19:16:15.969+0100|INFO|glassfish3.1.1|javax.enterprise.system.tools.admin.org.glassfish.server|_ThreadID=16;_ThreadName=Thread-24;|JMXStartupService: Started JMXConnector, JMXService URL = service:jmx:rmi://XX.XX.XX.XX:8686/jndi/rmi://XX.XX.XX.XX:8686/jmxrmi|#] [#|2011-12-26T19:16:16.450+0100|INFO|glassfish3.1.1|javax.enterprise.system.std.com.sun.enterprise.server.logging|_ThreadID=17;_ThreadName=Gogo shell;|____________________________ Welcome to Apache Felix Gogo |#] |
Abrimos otra consola en la misma ruta y ejecutamos el comando «asadmin».
1 2 |
MacBook-Pro-de-Carlos:bin cleon$ ./asadmin Utilice "exit" para salir y "help" para obtener ayuda en l?nea. |
El primer paso será crear el cluster, al que llamaremos «cluster»:
1 2 |
asadmin> create-cluster cluster El comando create-cluster se ha ejecutado correctamente. |
Después creamos los dos nodos que compondrán el cluster, «node1» y «node2»:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
asadmin> create-local-instance --cluster cluster node1 Rendezvoused with DAS on localhost:4848. Asignaciones de puerto para instancia de servidor node1: JMX_SYSTEM_CONNECTOR_PORT=28686 JMS_PROVIDER_PORT=27676 HTTP_LISTENER_PORT=28080 ASADMIN_LISTENER_PORT=24848 JAVA_DEBUGGER_PORT=29009 IIOP_SSL_LISTENER_PORT=23820 IIOP_LISTENER_PORT=23700 OSGI_SHELL_TELNET_PORT=26666 HTTP_SSL_LISTENER_PORT=28181 IIOP_SSL_MUTUALAUTH_PORT=23920 El comando create-local-instance se ha ejecutado correctamente. asadmin> create-local-instance --cluster cluster node2 Rendezvoused with DAS on localhost:4848. Using DAS host localhost and port 4848 from existing das.properties for node localhost-domain1. To use a different DAS, create a new node using create-node-ssh or create-node-config. Create the instance with the new node and correct host and port: asadmin --host das_host --port das_port create-local-instance --node node_name instance_name. Asignaciones de puerto para instancia de servidor node2: JMX_SYSTEM_CONNECTOR_PORT=28687 JMS_PROVIDER_PORT=27677 HTTP_LISTENER_PORT=28081 ASADMIN_LISTENER_PORT=24849 JAVA_DEBUGGER_PORT=29010 IIOP_SSL_LISTENER_PORT=23821 IIOP_LISTENER_PORT=23701 OSGI_SHELL_TELNET_PORT=26667 HTTP_SSL_LISTENER_PORT=28182 IIOP_SSL_MUTUALAUTH_PORT=23921 El comando create-local-instance se ha ejecutado correctamente. |
Ahora asociaremos dos propiedades genericas para cada nodo del cluster para su comunicación con el mod_jk (el nombre del nodo y el puerto):
1 2 3 4 5 6 |
asadmin> create-jvm-options --target cluster "-DjvmRoute=\\${AJP_INSTANCE_NAME}" Se han creado 1 opciones El comando create-jvm-options se ha ejecutado correctamente. asadmin> create-jvm-options --target cluster "-Dcom.sun.enterprise.web.connector.enableJK=\\${AJP_PORT}" Se han creado 1 opciones El comando create-jvm-options se ha ejecutado correctamente. |
Ahora establecemos las dos propiedades para cada nodo del cluster:
1 2 3 4 5 6 7 8 |
asadmin> create-system-properties --target node1 AJP_INSTANCE_NAME=node1 El comando create-system-properties se ha ejecutado correctamente. asadmin> create-system-properties --target node2 AJP_INSTANCE_NAME=node2 El comando create-system-properties se ha ejecutado correctamente. asadmin> create-system-properties --target node1 AJP_PORT=8009 El comando create-system-properties se ha ejecutado correctamente. asadmin> create-system-properties --target node2 AJP_PORT=8010 El comando create-system-properties se ha ejecutado correctamente. |
Iniciamos el cluster:
1 2 |
asadmin> start-cluster cluster El comando start-cluster se ha ejecutado correctamente. |
Una vez realizados estos pasos, ya tenemos el cluster configurado para atender peticiones. Si cargamos la instancia de administración: http://localhost:4848/common/index.jsf logandonos con las credenciales
introducidas en la instalación, podemos ver toda la configuración del cluster introducida.
Los pasos anteriormente mencionados tambien los podriamos haber hecho mediante la herramienta de administración web, pero he optado por utilizar el comando asadmin ya que es mas potente.





5. Aplicación
Crearemos un nuevo proyecto maven3 con la siguiente estructura (es la misma aplicación que utilizamos en el tutorial de clustering con Tomcat http://www.adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=tomcat7clusterjsf):

Ahora crearemos el pom.xml, en el cual nuestro objetivo será crear un paquete WAR para desplegarlo en Glassfish, y definir las dependencias con las librerías necesarias para trabajar con JSF:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.autentia</groupId> <artifactId>jsfcluster</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>jsfcluster</name> <description>Pruebas de clustering con jsf</description> <build> <finalName>${project.artifactId}</finalName> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>javax.faces</groupId> <artifactId>jsf-api</artifactId> <version>1.2_15</version> </dependency> <dependency> <groupId>javax.faces</groupId> <artifactId>jsf-impl</artifactId> <version>1.2_15</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.1</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>javax.el</groupId> <artifactId>el-api</artifactId> <version>2.2</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> </dependencies> </project> |
El siguiente paso es la configuración de jsf en el web.xml, para que atienda todas las peticiones .jsf:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <display-name>jsfcluster</display-name> <welcome-file-list> <welcome-file>home.jsf</welcome-file> </welcome-file-list> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.jsf</url-pattern> </servlet-mapping> <distributable/> </web-app> |
Ahora definiremos un ManagedBean con el scope session:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
package com.autentia.jsfcluster.beans; import java.io.Serializable; /** * @author cleon * */ public class Texto implements Serializable { private static final long serialVersionUID = -330458269625644065L; private String texto; public Texto() { } public String getTexto() { return texto; } public void setTexto(String texto) { this.texto = texto; } } |
Y un listener para ver el ciclo de vida de la aplicación desde el que mostraremos el contenido de la sesión en cada petición:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
package com.autentia.jsfcluster.listener; import java.util.Enumeration; import javax.faces.event.PhaseEvent; import javax.faces.event.PhaseId; import javax.faces.event.PhaseListener; import javax.servlet.http.HttpSession; import org.apache.commons.lang3.builder.ToStringBuilder; /** * @author cleon * */ public class ListenerPhase implements PhaseListener { private static final long serialVersionUID = 1L; @Override public void afterPhase(PhaseEvent pe) {} @Override public void beforePhase(PhaseEvent pe) { System.out.println("POST-FASE: " + pe.getPhaseId()); if (pe.getPhaseId() == PhaseId.RESTORE_VIEW){ HttpSession session = (HttpSession)pe.getFacesContext().getExternalContext().getSession(false); if (session!=null){ Enumeration<String> atributos = session.getAttributeNames(); String nombreAtributo = ""; System.out.println("Atributos en sesion: "); while (atributos.hasMoreElements()){ nombreAtributo = atributos.nextElement(); System.out.println("\tAtributo: " + nombreAtributo); Object atributo = session.getAttribute(nombreAtributo); System.out.println("\tValor: " + ToStringBuilder.reflectionToString(atributo)); } }else{ System.out.println("La session es nula: " + session); } } } @Override public PhaseId getPhaseId() { return PhaseId.ANY_PHASE; } } |
Creamos la vista home.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <f:view> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Pruebas con clustering jsf</title> </head> <body> <h3>Pruebas con clustering:</h3> <% out.println("NODOX<br/>"); System.out.println("NODOX"); if ( session.isNew() ) { %> Sesion nueva: <% out.println(session.getId()); } else { %> Sesion existente: <% out.println(session.getId()); }%> <br/> <h:form> <h:outputLabel value="Introduce un texto: " /><h:inputText label="texto" value="#{texto.texto}"></h:inputText><br/> <h:commandButton label="Submit" value="Submit"/><br/> El texto introducido es: {texto.texto} </h:form> </body> </html> </f:view> |
Por último la configuración de ambos en el faces-config.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?xml version="1.0" encoding="UTF-8"?> <faces-config version="1.2" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xi="http://www.w3.org/2001/XInclude" 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-facesconfig_1_2.xsd"> <managed-bean> <managed-bean-name>texto</managed-bean-name> <managed-bean-class>com.autentia.jsfcluster.beans.Texto</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> <lifecycle> <phase-listener>com.autentia.jsfcluster.listener.ListenerPhase</phase-listener> </lifecycle> </faces-config> |
Cuando tengamos el proyecto con todas sus partes tan solo tenemos que ejecutar un mvn clean package que nos generará el archivo jsfcluster.war en la carpeta target.
6. Despliegue
Una vez generado el war lo desplegamos desde la herramienta de administración web, seleccionando el cluster, la pestaña Applications, botón Implementar:

Seleccionamos nuestro archivo local:

Marcamos la casilla «Disponibilidad» para que tenga replicación de sesión (este parámetro en conjunto con <distributable/> del «web.xml» lo hacen posible), tambien asociaremos nuestro cluster como destino seleccionado (lo suele poner por defecto):


Y ya tenemos nuestra aplicación desplegada:

Cuando esté desplegado en ambos servidores modificamos la vista en la ruta «<GLASHFISH_HOME>/glassfishv3/glassfish/nodes/localhost-domain1/nodeX/applications/jsfcluster/home.jsp para cambiar las líneas que identificarán el nodo que atiende la petición (modificar la X por 1 ó 2 en cada caso):
1 2 |
out.println("NODOX<br/>"); System.out.println("NODOX"); |
7. Prueba de balanceo
Si todo ha ido bien, debemos estar en condiciones de realizar una peticion al apache con la siguiente url http://localhost/jsfcluster/home.jsf

Ahora rellenamos el campo de texto y realizamos peticiones consecutivas sobre el boton, verificando que se va variando de nodo en cada petición:


Si revisamos los logs de ambos servidores («<GLASHFISH_HOME>/glassfishv3/glassfish/nodes/localhost-domain1/nodeX/logs/server.log), veremos que la sesion es la misma en cada caso:
1 2 3 4 5 6 7 |
Atributos en sesion: Atributo: com.sun.faces.logicalViewMap Valor: com.sun.faces.util.LRUMap@ccc621[maxCapacity=15,accessOrder=true,threshold=16,loadFactor=1.0] Atributo: texto Valor: com.autentia.jsfcluster.beans.Texto@1e3bfb6[texto=Prueba Autentia!] Atributo: javax.faces.request.charset Valor: java.lang.String@13f5a2f[value={U,T,F,-,8},offset=0,count=5,hash=81070450] |
Donde se identifican los managed beans (en nuestro caso texto) y su valor, y el arbol de componentes jsf (que debe ser exactamente el mismo en los dos nodos).
8. Problemas encontrados
Esta prueba es totalmente funcional con JSF, la versión 1.2_15 concretamente. La misma prueba la hemos realizado sobre JSF2 2.1.4 (implementación Sun Mojarra) realizando la replica de sesión correctamente (con algunos ajustes finos necesarios), contrariamente a lo que sucedía con Tomcat.
Según aporta Oracle en las notas de la release http://javaserverfaces.java.net/nonav/rlnotes/2.1.4/issues.html no está probada con Tomcat ni Jetty, con lo que esperamos que en un futuro las posteriores versiones estén
validadas en estos servidores.
9. Conclusiones
Como comentaba en el anterior punto, este ejemplo es extrapolable a otro tipo de aplicaciones, ya que es la configuración básica de un glassfish en cluster con replicación de sesión. Por lo menos hemos podido comprobar que jsf2 funciona en clustering,
aunque sea sobre las plataformas Oracle.
Cualquier duda o sugerencia podeis comentarlo.
Saludos.
[…] Formato de la petición a enviar al servicio web. […]